<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 syscall::SigAction;

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

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 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(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 execve(prog: &str, args: &[&str], clear_env: bool) -> io::Result<()> {
    // 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!
        cvt(syscall::execve(prog.as_os_str().as_bytes(), &cvt_args)).and(Ok(()))
    } else {
        // The binary was not found.
        Err(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, TERMINATED};
    use std::os::unix::process::ExitStatusExt;
    use std::process::ExitStatus;
    use std::sync::{Arc, Mutex};
    use syscall;

    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<F, D>(
        shell: &mut Shell,
        _pid: u32,
        last_pid: u32,
        _get_command: F,
        mut drop_command: D,
    ) -> i32
    where
        F: FnOnce() -> String,
        D: FnMut(i32),
    {
        let mut exit_status = 0;
        loop {
            let mut status_raw = 0;
            match syscall::waitpid(0, &mut status_raw, 0) {
                Ok(pid) => {
                    let status = ExitStatus::from_raw(status_raw as i32);
                    if let Some(code) = status.code() {
                        if pid == (last_pid as usize) {
                            break code;
                        } else {
                            drop_command(pid as i32);
                            exit_status = code;
                        }
                    } else if let Some(signal) = status.signal() {
                        eprintln!("ion: process ended by signal: {}", signal);
                        if signal == syscall::SIGTERM as i32 {
                            shell.handle_signal(signal);
                            shell.exit(TERMINATED);
                        } else if signal == syscall::SIGHUP as i32 {
                            shell.handle_signal(signal);
                            shell.exit(TERMINATED);
                        } else if signal == syscall::SIGINT as i32 {
                            shell.foreground_send(signal);
                            shell.break_flow = true;
                        }
                        break TERMINATED;
                    } else {
                        eprintln!("ion: process ended with unknown status: {}", status);
                        break TERMINATED;
                    }
                }
                Err(err) => if err.errno == syscall::ECHILD {
                    break exit_status;
                } else {
                    eprintln!("ion: process doesn't exist: {}", err);
                    break FAILURE;
                },
            }
        }
    }
}

pub mod variables {
    pub(crate) fn get_user_home(_username: &str) -> Option<String> {
        // TODO
        None
    }
}
<commit_msg>Fix type casts in sys::redox<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 syscall::SigAction;

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

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 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(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 execve(prog: &str, args: &[&str], clear_env: bool) -> io::Result<()> {
    // 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!
        cvt(syscall::execve(prog.as_os_str().as_bytes(), &cvt_args)).and(Ok(()))
    } else {
        // The binary was not found.
        Err(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, TERMINATED};
    use std::os::unix::process::ExitStatusExt;
    use std::process::ExitStatus;
    use std::sync::{Arc, Mutex};
    use syscall;

    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<F, D>(
        shell: &mut Shell,
        _pid: u32,
        last_pid: u32,
        _get_command: F,
        mut drop_command: D,
    ) -> i32
    where
        F: FnOnce() -> String,
        D: FnMut(i32),
    {
        let mut exit_status = 0;
        loop {
            let mut status_raw = 0;
            match syscall::waitpid(0, &mut status_raw, 0) {
                Ok(pid) => {
                    let status = ExitStatus::from_raw(status_raw as i32);
                    if let Some(code) = status.code() {
                        if pid == (last_pid as usize) {
                            break code;
                        } else {
                            drop_command(pid as i32);
                            exit_status = code;
                        }
                    } else if let Some(signal) = status.signal() {
                        eprintln!("ion: process ended by signal: {}", signal);
                        if signal == syscall::SIGTERM as i32 {
                            shell.handle_signal(signal);
                            shell.exit(TERMINATED);
                        } else if signal == syscall::SIGHUP as i32 {
                            shell.handle_signal(signal);
                            shell.exit(TERMINATED);
                        } else if signal == syscall::SIGINT as i32 {
                            shell.foreground_send(signal);
                            shell.break_flow = true;
                        }
                        break TERMINATED;
                    } else {
                        eprintln!("ion: process ended with unknown status: {}", status);
                        break TERMINATED;
                    }
                }
                Err(err) => if err.errno == syscall::ECHILD {
                    break exit_status;
                } else {
                    eprintln!("ion: process doesn't exist: {}", err);
                    break FAILURE;
                },
            }
        }
    }
}

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


<commit_before>//! Apps should not need to concern themselves with this module.
//!
//! Crates which add new types which allow numeric operators should implement these traits to
//! specify what the output is for a given right hand side

/// Represents SQL types which can be added.
///
/// Similar to `std::ops::Add`, but this only includes information about the SQL types that will
/// result from the operation. Unlike `std::ops::Add`, the right side is an associated type rather
/// than a type parameter. This means that a given SQL type can only have one other SQL type added
/// to it. The reason for this is that when the right side is a Rust value which would be sent as a
/// bind parameter, we need to know which type to use.
pub trait Add {
    /// The SQL type which can be added to this one
    type Rhs;
    /// The SQL type of the result of adding `Rhs` to `Self`
    type Output;
}

/// Represents SQL types which can be subtracted.
///
/// Similar to `std::ops::Sub`, but this only includes information about the SQL types that will
/// result from the operation. Unlike `std::ops::Sub`, the right side is an associated type rather
/// than a type parameter. This means that a given SQL type can only have one other SQL type
/// subtracted from it. The reason for this is that when the right side is a Rust value which would
/// be sent as a bind parameter, we need to know which type to use.
pub trait Sub {
    /// The SQL type which can be subtracted from this one
    type Rhs;
    /// The SQL type of the result of subtracting `Rhs` from `Self`
    type Output;
}

/// Represents SQL types which can be multiplied.
///
/// Similar to `std::ops::Mul`, but this only includes information about the SQL types that will
/// result from the operation. Unlike `std::ops::Mul`, the right side is an associated type rather
/// than a type parameter. This means that a given SQL type can only have one other SQL type
/// multiplied with it. The reason for this is that when the right side is a Rust value which
/// would be sent as a bind parameter, we need to know which type to use.
pub trait Mul {
    /// The SQL type which this can be multiplied by
    type Rhs;
    /// The SQL type of the result of multiplying `Self` by `Rhs`
    type Output;
}

/// Represents SQL types which can be divided.
///
/// Similar to `std::ops::Div`, but this only includes information about the SQL types that will
/// result from the operation. Unlike `std::ops::Div`, the right side is an associated type rather
/// than a type parameter. This means that a given SQL type can only be divided by one other SQL
/// type. The reason for this is that when the right side is a Rust value which would be sent as a
/// bind parameter, we need to know which type to use.
pub trait Div {
    /// The SQL type which this one can be divided by
    type Rhs;
    /// The SQL type of the result of dividing `Self` by `Rhs`
    type Output;
}

macro_rules! numeric_type {
    ($($tpe: ident),*) => {
        $(
        impl Add for super::$tpe {
            type Rhs = super::$tpe;
            type Output = super::$tpe;
        }

        impl Add for super::Nullable<super::$tpe> {
            type Rhs = super::Nullable<super::$tpe>;
            type Output = super::Nullable<super::$tpe>;
        }

        impl Sub for super::$tpe {
            type Rhs = super::$tpe;
            type Output = super::$tpe;
        }

        impl Sub for super::Nullable<super::$tpe> {
            type Rhs = super::Nullable<super::$tpe>;
            type Output = super::Nullable<super::$tpe>;
        }

        impl Mul for super::$tpe {
            type Rhs = super::$tpe;
            type Output = super::$tpe;
        }

        impl Mul for super::Nullable<super::$tpe> {
            type Rhs = super::Nullable<super::$tpe>;
            type Output = super::Nullable<super::$tpe>;
        }

        impl Div for super::$tpe {
            type Rhs = super::$tpe;
            type Output = super::$tpe;
        }

        impl Div for super::Nullable<super::$tpe> {
            type Rhs = super::Nullable<super::$tpe>;
            type Output = super::Nullable<super::$tpe>;
        }
        )*
    }
}

numeric_type!(SmallInt, Integer, BigInt, Float, Double, Numeric);

impl Add for super::Timestamp {
    type Rhs = super::Interval;
    type Output = super::Timestamp;
}

impl Sub for super::Timestamp {
    type Rhs = super::Interval;
    type Output = super::Timestamp;
}

impl Add for super::Date {
    type Rhs = super::Interval;
    type Output = super::Timestamp;
}

impl Sub for super::Date {
    type Rhs = super::Interval;
    type Output = super::Timestamp;
}
<commit_msg>Implement Add/Sub for Nullable<Date/Timestamp><commit_after>//! Apps should not need to concern themselves with this module.
//!
//! Crates which add new types which allow numeric operators should implement these traits to
//! specify what the output is for a given right hand side

/// Represents SQL types which can be added.
///
/// Similar to `std::ops::Add`, but this only includes information about the SQL types that will
/// result from the operation. Unlike `std::ops::Add`, the right side is an associated type rather
/// than a type parameter. This means that a given SQL type can only have one other SQL type added
/// to it. The reason for this is that when the right side is a Rust value which would be sent as a
/// bind parameter, we need to know which type to use.
pub trait Add {
    /// The SQL type which can be added to this one
    type Rhs;
    /// The SQL type of the result of adding `Rhs` to `Self`
    type Output;
}

/// Represents SQL types which can be subtracted.
///
/// Similar to `std::ops::Sub`, but this only includes information about the SQL types that will
/// result from the operation. Unlike `std::ops::Sub`, the right side is an associated type rather
/// than a type parameter. This means that a given SQL type can only have one other SQL type
/// subtracted from it. The reason for this is that when the right side is a Rust value which would
/// be sent as a bind parameter, we need to know which type to use.
pub trait Sub {
    /// The SQL type which can be subtracted from this one
    type Rhs;
    /// The SQL type of the result of subtracting `Rhs` from `Self`
    type Output;
}

/// Represents SQL types which can be multiplied.
///
/// Similar to `std::ops::Mul`, but this only includes information about the SQL types that will
/// result from the operation. Unlike `std::ops::Mul`, the right side is an associated type rather
/// than a type parameter. This means that a given SQL type can only have one other SQL type
/// multiplied with it. The reason for this is that when the right side is a Rust value which
/// would be sent as a bind parameter, we need to know which type to use.
pub trait Mul {
    /// The SQL type which this can be multiplied by
    type Rhs;
    /// The SQL type of the result of multiplying `Self` by `Rhs`
    type Output;
}

/// Represents SQL types which can be divided.
///
/// Similar to `std::ops::Div`, but this only includes information about the SQL types that will
/// result from the operation. Unlike `std::ops::Div`, the right side is an associated type rather
/// than a type parameter. This means that a given SQL type can only be divided by one other SQL
/// type. The reason for this is that when the right side is a Rust value which would be sent as a
/// bind parameter, we need to know which type to use.
pub trait Div {
    /// The SQL type which this one can be divided by
    type Rhs;
    /// The SQL type of the result of dividing `Self` by `Rhs`
    type Output;
}

macro_rules! numeric_type {
    ($($tpe: ident),*) => {
        $(
        impl Add for super::$tpe {
            type Rhs = super::$tpe;
            type Output = super::$tpe;
        }

        impl Add for super::Nullable<super::$tpe> {
            type Rhs = super::Nullable<super::$tpe>;
            type Output = super::Nullable<super::$tpe>;
        }

        impl Sub for super::$tpe {
            type Rhs = super::$tpe;
            type Output = super::$tpe;
        }

        impl Sub for super::Nullable<super::$tpe> {
            type Rhs = super::Nullable<super::$tpe>;
            type Output = super::Nullable<super::$tpe>;
        }

        impl Mul for super::$tpe {
            type Rhs = super::$tpe;
            type Output = super::$tpe;
        }

        impl Mul for super::Nullable<super::$tpe> {
            type Rhs = super::Nullable<super::$tpe>;
            type Output = super::Nullable<super::$tpe>;
        }

        impl Div for super::$tpe {
            type Rhs = super::$tpe;
            type Output = super::$tpe;
        }

        impl Div for super::Nullable<super::$tpe> {
            type Rhs = super::Nullable<super::$tpe>;
            type Output = super::Nullable<super::$tpe>;
        }
        )*
    }
}

numeric_type!(SmallInt, Integer, BigInt, Float, Double, Numeric);

macro_rules! interval_type {
    ($($tpe: ident),*) => {
        $(
        impl Add for super::$tpe {
            type Rhs = super::Interval;
            type Output = super::$tpe;
        }

        impl Add for super::Nullable<super::$tpe> {
            type Rhs = super::Nullable<super::Interval>;
            type Output = super::Nullable<super::$tpe>;
        }

        impl Sub for super::$tpe {
            type Rhs = super::Interval;
            type Output = super::$tpe;
        }

        impl Sub for super::Nullable<super::$tpe> {
            type Rhs = super::Nullable<super::Interval>;
            type Output = super::Nullable<super::$tpe>;
        }
        )*
    }
}

interval_type!(Date, Timestamp);
<|endoftext|>


<commit_before>extern crate resp;
extern crate rusqlite;

use self::resp::{Value};
use self::rusqlite::{Connection};
use std::sync::{Arc, Mutex, MutexGuard};
use std::cmp;

type CommandResult = Result<Value, String>;

struct Command<'a> {
    name: String,
    arguments: Vec<&'a String>,
    connection_mutex: &'a Arc<Mutex<Connection>>
}

struct CommandSettings {
    name: &'static str,
    argument_count: i32,
    //handler: fn(&'a Command<'a>) -> CommandResult
}

enum Direction {
    Left,
    Right
}

const COMMAND_SETTINGS: [CommandSettings; 10] = [
    CommandSettings { name: "LLEN", argument_count: 1 }, //, handler: Command::llen }
    CommandSettings { name: "LPOP", argument_count: 1 },
    CommandSettings { name: "RPOP", argument_count: 1 },
    CommandSettings { name: "LPUSH", argument_count: -2 },
    CommandSettings { name: "RPUSH", argument_count: -2 },
    CommandSettings { name: "LRANGE", argument_count: 3 },
    CommandSettings { name: "LTRIM", argument_count: 3 },
    CommandSettings { name: "RPOPLPUSH", argument_count: 2 },
    CommandSettings { name: "LINDEX", argument_count: 2 },
    CommandSettings { name: "LSET", argument_count: 3 },
];

pub fn handle_input(ref value: Value, connection_mutex: &Arc<Mutex<Connection>>) -> (Value, bool) {
    match parse_command(value, connection_mutex) {
        Ok(mut command) => { command.handle_command() }
        Err(error)  => { (Value::Error(format!("ERR {}", error)), false) }
    }
}

fn parse_command<'a>(value: &'a Value, connection_mutex: &'a Arc<Mutex<Connection>>) -> Result<Command<'a>, &'static str> {
    if let &Value::Array(ref array) = value {
        parse_command_array(array, connection_mutex)
    }
    else {
        Err("expected array")
    }
}

fn parse_command_array<'a>(array: &'a Vec<Value>, connection_mutex: &'a Arc<Mutex<Connection>>) -> Result<Command<'a>, &'static str> {
    let iter = array.iter().map(|value|
        match *value {
            Value::String(ref string) | Value::Bulk(ref string) => Ok(string),
            _ => Err("all arguments should be strings")
        }
    );

    let strings = iter.collect::<Result<Vec<&String>, &'static str>>()?;
    let (head, tail) = strings.split_at(1);

    Ok(Command {
        name: head[0].to_uppercase(),
        arguments: tail.to_vec(),
        connection_mutex: connection_mutex
    })
}

impl<'a> Command<'a> {
    fn handle_command(&mut self) -> (Value, bool) {
        print!("command {}\n", self.name);

        match self.name.as_ref() {
            "QUIT" => (Value::String("OK".to_string()), true),
            _      => (self.handle_nonterminal_command(), false)
        }
    }

    fn valid_argument_count(&self, command: &CommandSettings) -> bool {
        (command.argument_count < 0 && self.arguments.len() as i32 >= -command.argument_count) ||
            (command.argument_count >= 0 && self.arguments.len() as i32 == command.argument_count)
    }

    fn handle_nonterminal_command(&mut self) -> Value {
        let all = COMMAND_SETTINGS;
        let settings = all.iter().find(|settings| settings.name == self.name);

        match settings {
            Some(settings) => {
                if self.valid_argument_count(settings) {
                    let result = match settings.name {
                        "LLEN" => self.llen(),
                        "LPUSH" => self.lpush(),
                        "RPUSH" => self.rpush(),
                        "LPOP" => self.lpop(),
                        "RPOP" => self.rpop(),
                        "LRANGE" => self.lrange(),
                        "LTRIM" => self.ltrim(),
                        "RPOPLPUSH" => self.rpoplpush(),
                        "LINDEX" => self.lindex(),
                        "LSET" => self.lset(),
                        _ => unimplemented!(),
                    };

                    match result {
                        Ok(value)  => value,
                        Err(error) => Value::Error(format!("ERR {}", error))
                    }
                }
                else {
                    Value::Error("ERR wrong number of arguments".to_string())
                }
            }

            None => Value::Error("ERR unsupported".to_string())
        }
    }

    fn llen(&self) -> CommandResult {
        let key = self.arguments[0];

        let connection = self.lock_connection();
        self.count_list_items_value(&*connection, key)
    }

    fn lpop(&self) -> CommandResult {
        let connection = self.lock_connection();

        match self.pop(&*connection, self.arguments[0], Direction::Left) {
            Some(data) => Ok(Value::Bulk(data)),
            None       => Ok(Value::NullArray)
        }
    }

    fn rpop(&self) -> CommandResult {
        let connection = self.lock_connection();

        match self.pop(&*connection, self.arguments[0], Direction::Right) {
            Some(data) => Ok(Value::Bulk(data)),
            None       => Ok(Value::NullArray)
        }
    }

    fn lpush(&self) -> CommandResult {
        let key = self.arguments[0];
        let mut connection = self.lock_connection();

        self.push(&mut *connection, key, Direction::Left, self.arguments.iter().skip(1));

        self.count_list_items_value(&*connection, key)
    }

    fn rpush(&self) -> CommandResult {
        let key = self.arguments[0];
        let mut connection = self.lock_connection();

        self.push(&mut *connection, key, Direction::Right, self.arguments.iter().skip(1));

        self.count_list_items_value(&*connection, key)
    }

    fn lrange(&self) -> CommandResult {
        let key = self.arguments[0];
        let mut start: i64 = self.arguments[1].parse().map_err(|_| "start must be an integer")?;
        let mut stop: i64 = self.arguments[2].parse().map_err(|_| "stop must be an integer")?;

        let connection = self.lock_connection();

        // LATER : maybe use find_position_boundaries and parse_indexes instead of this
        // this needs only one select rather than two in the case where start and stop >= 0
        // but then it uses order & limit which are probably slower on a huge table
        // investigate performance at a later date

        if start < 0 || stop < -1 {
            let count = self.count_list_items(&connection, key);

            if start < 0  { start = cmp::max(0, count + start) }

            if stop < -1 {
                stop = count + stop;
                if stop < 0 { return Ok(Value::Array(vec![])); }
            }
        }

        if stop != -1 && start > stop { return Ok(Value::Array(vec![])); }

        let sql = match (start, stop) {
            (0, -1) => "".to_string(),
            (a, -1) => format!("LIMIT -1 OFFSET {}", a),
            (0, b)  => format!("LIMIT {}", b + 1),
            (a, b)  => format!("LIMIT {} OFFSET {}", b - a + 1, a),
        };

        let mut statement = connection.prepare(&format!("SELECT value FROM list_items WHERE key = ?1 ORDER BY position {}", sql)).unwrap();
        let rows = statement.query_map(&[key], |row| row.get(0)).unwrap();
        let result: Result<Vec<String>, _> = rows.collect();
        let values = result.unwrap().iter().map(|value| Value::String(value.clone())).collect();

        Ok(Value::Array(values))
    }

    fn ltrim(&self) -> CommandResult {
        let key = self.arguments[0];
        let start: i64 = self.arguments[1].parse().map_err(|_| "start must be an integer")?;
        let stop: i64 = self.arguments[2].parse().map_err(|_| "stop must be an integer")?;

        if start != 0 || stop != -1 {
            let connection = self.lock_connection();

            let boundaries = self.find_position_boundaries(&*connection, key);
            let (start_position, stop_position) = self.parse_indexes(boundaries, (start, stop));

            connection.execute("DELETE FROM list_items WHERE key = ?1 AND (position < ?2 OR position > ?3)", &[key, &start_position, &stop_position]).unwrap();
        }

        Ok(Value::String("OK".to_string()))
    }

    fn rpoplpush(&self) -> CommandResult {
        let source = self.arguments[0];
        let destination = self.arguments[1];

        let mut connection = self.lock_connection();

        match self.pop(&*connection, source, Direction::Right) {
            Some(data) => {
                self.push(&mut *connection, destination, Direction::Left, [&data].iter());
                Ok(Value::Bulk(data))
            }

            None => Ok(Value::NullArray)
        }
    }

    fn lindex(&self) -> CommandResult {
        let key = self.arguments[0];
        let index: i64 = self.arguments[1].parse().map_err(|_| "index must be an integer")?;

        let connection = self.lock_connection();

        let boundaries = self.find_position_boundaries(&*connection, key);
        let position = self.parse_index(boundaries, index);

        let mut statement = connection.prepare("SELECT value FROM list_items WHERE key = ?1 AND position = ?2 LIMIT 1").unwrap();

        match statement.query_row(&[key, &position], |row| row.get(0)) {
            Ok(data)                                  => Ok(Value::Bulk(data)),
            Err(rusqlite::Error::QueryReturnedNoRows) => Ok(Value::NullArray),
            Err(e)                                    => panic!(e)
        }
    }

    fn lset(&self) -> CommandResult {
        let key = self.arguments[0];
        let index: i64 = self.arguments[1].parse().map_err(|_| "index must be an integer")?;
        let data = self.arguments[2];

        let connection = self.lock_connection();

        let (first_position, last_position) = self.find_position_boundaries(&*connection, key);
        let position = self.parse_index((first_position, last_position), index);

        if position < first_position || position > last_position {
            Err("index out of range".to_string())
        }
        else {
            connection.execute("UPDATE list_items SET value = ?1 WHERE key = ?2 AND position = ?3", &[data, key, &position]).unwrap();
            Ok(Value::String("OK".to_string()))
        }
    }

    // private

    fn pop(&self, connection: &Connection, key: &String, direction: Direction) -> Option<String> {
        let order = match direction { Direction::Left => "ASC", Direction::Right => "DESC" };
        let mut statement = connection.prepare(&format!("SELECT id, value FROM list_items WHERE key = ?1 ORDER BY position {} LIMIT 1", order)).unwrap();

        match statement.query_row(&[key], |row| (row.get(0), row.get(1))) {
            Ok(result) => {
                let (id, value): (i64, String) = result;

                connection.execute("DELETE FROM list_items WHERE id = ?1", &[&id]).unwrap();
                Some(value)
            }

            Err(rusqlite::Error::QueryReturnedNoRows) => None,

            Err(e) => Err(e).unwrap()
        }
    }

    fn push<'b, I>(&self, connection: &mut Connection, key: &String, direction: Direction, iterator: I) -> ()
        where I: Iterator<Item=&'b &'b String>
    {
        let tx = connection.transaction().unwrap();

        let next_position_sql = match direction {
            Direction::Left  => "coalesce(MIN(position), 0) - 1",
            Direction::Right => "coalesce(MAX(position), 0) + 1"
        };

        let sql = format!("INSERT INTO list_items (key, value, position) SELECT ?1, ?2, {} FROM list_items WHERE key = ?1", next_position_sql);

        iterator.map(|value| tx.execute(&sql, &[key, *value])).collect::<Result<Vec<_>, _>>().unwrap();

        tx.commit().unwrap();
    }

    fn lock_connection(&self) -> MutexGuard<Connection> {
        (*self.connection_mutex).lock().unwrap()
    }

    fn find_position_boundaries(&self, connection: &Connection, key: &String) -> (i64, i64) {
        let mut statement = connection.prepare("SELECT MIN(position), MAX(position) AS c FROM list_items WHERE key = ?1").unwrap();
        statement.query_row(&[key], |row| (row.get(0), row.get(1))).unwrap()
    }

    fn parse_indexes(&self, boundaries: (i64, i64), (start, stop): (i64, i64)) -> (i64, i64) {
        (self.parse_index(boundaries, start), self.parse_index(boundaries, stop))
    }

    fn parse_index(&self, (first_position, last_position): (i64, i64), index: i64) -> i64 {
        if index < 0 { index + last_position + 1 } else { index + first_position }
    }

    fn count_list_items(&self, connection: &Connection, key: &String) -> i64 {
        let mut statement = connection.prepare("SELECT COUNT(*) AS c FROM list_items WHERE key = ?1").unwrap();
        statement.query_row(&[key], |row| row.get(0)).unwrap()
    }

    fn count_list_items_value(&self, connection: &Connection, key: &String) -> CommandResult {
        Ok(Value::Integer(self.count_list_items(connection, key)))
    }
}
<commit_msg>lpushx and rpushx<commit_after>extern crate resp;
extern crate rusqlite;

use self::resp::{Value};
use self::rusqlite::{Connection};
use std::sync::{Arc, Mutex, MutexGuard};
use std::cmp;

type CommandResult = Result<Value, String>;

struct Command<'a> {
    name: String,
    arguments: Vec<&'a String>,
    connection_mutex: &'a Arc<Mutex<Connection>>
}

struct CommandSettings {
    name: &'static str,
    argument_count: i32,
    //handler: fn(&'a Command<'a>) -> CommandResult
}

enum Direction {
    Left,
    Right
}

const COMMAND_SETTINGS: [CommandSettings; 12] = [
    CommandSettings { name: "LLEN", argument_count: 1 }, //, handler: Command::llen }
    CommandSettings { name: "LPOP", argument_count: 1 },
    CommandSettings { name: "RPOP", argument_count: 1 },
    CommandSettings { name: "LPUSH", argument_count: -2 },
    CommandSettings { name: "LPUSHX", argument_count: -2 },
    CommandSettings { name: "RPUSH", argument_count: -2 },
    CommandSettings { name: "RPUSHX", argument_count: -2 },
    CommandSettings { name: "LRANGE", argument_count: 3 },
    CommandSettings { name: "LTRIM", argument_count: 3 },
    CommandSettings { name: "RPOPLPUSH", argument_count: 2 },
    CommandSettings { name: "LINDEX", argument_count: 2 },
    CommandSettings { name: "LSET", argument_count: 3 },
];

pub fn handle_input(ref value: Value, connection_mutex: &Arc<Mutex<Connection>>) -> (Value, bool) {
    match parse_command(value, connection_mutex) {
        Ok(mut command) => { command.handle_command() }
        Err(error)  => { (Value::Error(format!("ERR {}", error)), false) }
    }
}

fn parse_command<'a>(value: &'a Value, connection_mutex: &'a Arc<Mutex<Connection>>) -> Result<Command<'a>, &'static str> {
    if let &Value::Array(ref array) = value {
        parse_command_array(array, connection_mutex)
    }
    else {
        Err("expected array")
    }
}

fn parse_command_array<'a>(array: &'a Vec<Value>, connection_mutex: &'a Arc<Mutex<Connection>>) -> Result<Command<'a>, &'static str> {
    let iter = array.iter().map(|value|
        match *value {
            Value::String(ref string) | Value::Bulk(ref string) => Ok(string),
            _ => Err("all arguments should be strings")
        }
    );

    let strings = iter.collect::<Result<Vec<&String>, &'static str>>()?;
    let (head, tail) = strings.split_at(1);

    Ok(Command {
        name: head[0].to_uppercase(),
        arguments: tail.to_vec(),
        connection_mutex: connection_mutex
    })
}

impl<'a> Command<'a> {
    fn handle_command(&mut self) -> (Value, bool) {
        print!("command {}\n", self.name);

        match self.name.as_ref() {
            "QUIT" => (Value::String("OK".to_string()), true),
            _      => (self.handle_nonterminal_command(), false)
        }
    }

    fn valid_argument_count(&self, command: &CommandSettings) -> bool {
        (command.argument_count < 0 && self.arguments.len() as i32 >= -command.argument_count) ||
            (command.argument_count >= 0 && self.arguments.len() as i32 == command.argument_count)
    }

    fn handle_nonterminal_command(&mut self) -> Value {
        let all = COMMAND_SETTINGS;
        let settings = all.iter().find(|settings| settings.name == self.name);

        match settings {
            Some(settings) => {
                if self.valid_argument_count(settings) {
                    let result = match settings.name {
                        "LLEN" => self.llen(),
                        "LPUSH" => self.lpush(),
                        "LPUSHX" => self.lpushx(),
                        "RPUSH" => self.rpush(),
                        "RPUSHX" => self.rpushx(),
                        "LPOP" => self.lpop(),
                        "RPOP" => self.rpop(),
                        "LRANGE" => self.lrange(),
                        "LTRIM" => self.ltrim(),
                        "RPOPLPUSH" => self.rpoplpush(),
                        "LINDEX" => self.lindex(),
                        "LSET" => self.lset(),
                        _ => unimplemented!(),
                    };

                    match result {
                        Ok(value)  => value,
                        Err(error) => Value::Error(format!("ERR {}", error))
                    }
                }
                else {
                    Value::Error("ERR wrong number of arguments".to_string())
                }
            }

            None => Value::Error("ERR unsupported".to_string())
        }
    }

    fn llen(&self) -> CommandResult {
        let key = self.arguments[0];

        let connection = self.lock_connection();
        self.count_list_items_value(&*connection, key)
    }

    fn lpop(&self) -> CommandResult {
        let connection = self.lock_connection();

        match self.pop(&*connection, self.arguments[0], Direction::Left) {
            Some(data) => Ok(Value::Bulk(data)),
            None       => Ok(Value::NullArray)
        }
    }

    fn rpop(&self) -> CommandResult {
        let connection = self.lock_connection();

        match self.pop(&*connection, self.arguments[0], Direction::Right) {
            Some(data) => Ok(Value::Bulk(data)),
            None       => Ok(Value::NullArray)
        }
    }

    fn lpush(&self) -> CommandResult {
        let key = self.arguments[0];
        let mut connection = self.lock_connection();

        self.push(&mut *connection, key, Direction::Left, self.arguments.iter().skip(1));

        self.count_list_items_value(&*connection, key)
    }

    fn lpushx(&self) -> CommandResult {
        let key = self.arguments[0];
        let mut connection = self.lock_connection();

        if self.count_list_items(&*connection, key) == 0 {
            Ok(Value::Integer(0))
        }
        else {
            self.push(&mut *connection, key, Direction::Left, self.arguments.iter().skip(1));

            self.count_list_items_value(&*connection, key)
        }
    }

    fn rpush(&self) -> CommandResult {
        let key = self.arguments[0];
        let mut connection = self.lock_connection();

        self.push(&mut *connection, key, Direction::Right, self.arguments.iter().skip(1));

        self.count_list_items_value(&*connection, key)
    }

    fn rpushx(&self) -> CommandResult {
        let key = self.arguments[0];
        let mut connection = self.lock_connection();

        if self.count_list_items(&*connection, key) == 0 {
            Ok(Value::Integer(0))
        }
        else {
            self.push(&mut *connection, key, Direction::Right, self.arguments.iter().skip(1));

            self.count_list_items_value(&*connection, key)
        }
    }

    fn lrange(&self) -> CommandResult {
        let key = self.arguments[0];
        let mut start: i64 = self.arguments[1].parse().map_err(|_| "start must be an integer")?;
        let mut stop: i64 = self.arguments[2].parse().map_err(|_| "stop must be an integer")?;

        let connection = self.lock_connection();

        // LATER : maybe use find_position_boundaries and parse_indexes instead of this
        // this needs only one select rather than two in the case where start and stop >= 0
        // but then it uses order & limit which are probably slower on a huge table
        // investigate performance at a later date

        if start < 0 || stop < -1 {
            let count = self.count_list_items(&connection, key);

            if start < 0  { start = cmp::max(0, count + start) }

            if stop < -1 {
                stop = count + stop;
                if stop < 0 { return Ok(Value::Array(vec![])); }
            }
        }

        if stop != -1 && start > stop { return Ok(Value::Array(vec![])); }

        let sql = match (start, stop) {
            (0, -1) => "".to_string(),
            (a, -1) => format!("LIMIT -1 OFFSET {}", a),
            (0, b)  => format!("LIMIT {}", b + 1),
            (a, b)  => format!("LIMIT {} OFFSET {}", b - a + 1, a),
        };

        let mut statement = connection.prepare(&format!("SELECT value FROM list_items WHERE key = ?1 ORDER BY position {}", sql)).unwrap();
        let rows = statement.query_map(&[key], |row| row.get(0)).unwrap();
        let result: Result<Vec<String>, _> = rows.collect();
        let values = result.unwrap().iter().map(|value| Value::String(value.clone())).collect();

        Ok(Value::Array(values))
    }

    fn ltrim(&self) -> CommandResult {
        let key = self.arguments[0];
        let start: i64 = self.arguments[1].parse().map_err(|_| "start must be an integer")?;
        let stop: i64 = self.arguments[2].parse().map_err(|_| "stop must be an integer")?;

        if start != 0 || stop != -1 {
            let connection = self.lock_connection();

            let boundaries = self.find_position_boundaries(&*connection, key);
            let (start_position, stop_position) = self.parse_indexes(boundaries, (start, stop));

            connection.execute("DELETE FROM list_items WHERE key = ?1 AND (position < ?2 OR position > ?3)", &[key, &start_position, &stop_position]).unwrap();
        }

        Ok(Value::String("OK".to_string()))
    }

    fn rpoplpush(&self) -> CommandResult {
        let source = self.arguments[0];
        let destination = self.arguments[1];

        let mut connection = self.lock_connection();

        match self.pop(&*connection, source, Direction::Right) {
            Some(data) => {
                self.push(&mut *connection, destination, Direction::Left, [&data].iter());
                Ok(Value::Bulk(data))
            }

            None => Ok(Value::NullArray)
        }
    }

    fn lindex(&self) -> CommandResult {
        let key = self.arguments[0];
        let index: i64 = self.arguments[1].parse().map_err(|_| "index must be an integer")?;

        let connection = self.lock_connection();

        let boundaries = self.find_position_boundaries(&*connection, key);
        let position = self.parse_index(boundaries, index);

        let mut statement = connection.prepare("SELECT value FROM list_items WHERE key = ?1 AND position = ?2 LIMIT 1").unwrap();

        match statement.query_row(&[key, &position], |row| row.get(0)) {
            Ok(data)                                  => Ok(Value::Bulk(data)),
            Err(rusqlite::Error::QueryReturnedNoRows) => Ok(Value::NullArray),
            Err(e)                                    => panic!(e)
        }
    }

    fn lset(&self) -> CommandResult {
        let key = self.arguments[0];
        let index: i64 = self.arguments[1].parse().map_err(|_| "index must be an integer")?;
        let data = self.arguments[2];

        let connection = self.lock_connection();

        let (first_position, last_position) = self.find_position_boundaries(&*connection, key);
        let position = self.parse_index((first_position, last_position), index);

        if position < first_position || position > last_position {
            Err("index out of range".to_string())
        }
        else {
            connection.execute("UPDATE list_items SET value = ?1 WHERE key = ?2 AND position = ?3", &[data, key, &position]).unwrap();
            Ok(Value::String("OK".to_string()))
        }
    }

    // private

    fn pop(&self, connection: &Connection, key: &String, direction: Direction) -> Option<String> {
        let order = match direction { Direction::Left => "ASC", Direction::Right => "DESC" };
        let mut statement = connection.prepare(&format!("SELECT id, value FROM list_items WHERE key = ?1 ORDER BY position {} LIMIT 1", order)).unwrap();

        match statement.query_row(&[key], |row| (row.get(0), row.get(1))) {
            Ok(result) => {
                let (id, value): (i64, String) = result;

                connection.execute("DELETE FROM list_items WHERE id = ?1", &[&id]).unwrap();
                Some(value)
            }

            Err(rusqlite::Error::QueryReturnedNoRows) => None,

            Err(e) => Err(e).unwrap()
        }
    }

    fn push<'b, I>(&self, connection: &mut Connection, key: &String, direction: Direction, iterator: I) -> ()
        where I: Iterator<Item=&'b &'b String>
    {
        let tx = connection.transaction().unwrap();

        let next_position_sql = match direction {
            Direction::Left  => "coalesce(MIN(position), 0) - 1",
            Direction::Right => "coalesce(MAX(position), 0) + 1"
        };

        let sql = format!("INSERT INTO list_items (key, value, position) SELECT ?1, ?2, {} FROM list_items WHERE key = ?1", next_position_sql);

        iterator.map(|value| tx.execute(&sql, &[key, *value])).collect::<Result<Vec<_>, _>>().unwrap();

        tx.commit().unwrap();
    }

    fn lock_connection(&self) -> MutexGuard<Connection> {
        (*self.connection_mutex).lock().unwrap()
    }

    fn find_position_boundaries(&self, connection: &Connection, key: &String) -> (i64, i64) {
        let mut statement = connection.prepare("SELECT MIN(position), MAX(position) AS c FROM list_items WHERE key = ?1").unwrap();
        statement.query_row(&[key], |row| (row.get(0), row.get(1))).unwrap()
    }

    fn parse_indexes(&self, boundaries: (i64, i64), (start, stop): (i64, i64)) -> (i64, i64) {
        (self.parse_index(boundaries, start), self.parse_index(boundaries, stop))
    }

    fn parse_index(&self, (first_position, last_position): (i64, i64), index: i64) -> i64 {
        if index < 0 { index + last_position + 1 } else { index + first_position }
    }

    fn count_list_items(&self, connection: &Connection, key: &String) -> i64 {
        let mut statement = connection.prepare("SELECT COUNT(*) AS c FROM list_items WHERE key = ?1").unwrap();
        statement.query_row(&[key], |row| row.get(0)).unwrap()
    }

    fn count_list_items_value(&self, connection: &Connection, key: &String) -> CommandResult {
        Ok(Value::Integer(self.count_list_items(connection, key)))
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::io;
use std::path::Path;

#[cfg(unix)]
use tokio::net::UnixListener;
#[cfg(unix)]
use tokio::net::UnixStream;

use futures::stream;

use futures::stream::Stream;
use futures::Future;

use crate::assert_types::assert_send_stream;
use crate::socket::AnySocketAddr;
use crate::socket::StreamItem;
use crate::socket::ToClientStream;
use crate::socket::ToServerStream;
use crate::socket::ToSocketListener;
use crate::socket::ToTokioListener;
use crate::ServerConf;
use std::fmt;
#[cfg(unix)]
use std::os::unix::net::SocketAddr;
use std::path::PathBuf;
use std::pin::Pin;
use tokio::runtime::Handle;

#[derive(Debug, Clone, PartialEq)]
pub struct SocketAddrUnix(pub(crate) PathBuf);

impl From<PathBuf> for SocketAddrUnix {
    fn from(p: PathBuf) -> Self {
        SocketAddrUnix(p)
    }
}

impl From<&Path> for SocketAddrUnix {
    fn from(p: &Path) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl From<&str> for SocketAddrUnix {
    fn from(p: &str) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl From<String> for SocketAddrUnix {
    fn from(p: String) -> Self {
        SocketAddrUnix(p.into())
    }
}

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

#[cfg(unix)]
impl From<SocketAddr> for SocketAddrUnix {
    fn from(s: SocketAddr) -> Self {
        // can be unnamed
        SocketAddrUnix(s.as_pathname().unwrap_or(Path::new("")).to_owned())
    }
}

impl ToSocketListener for SocketAddrUnix {
    #[cfg(unix)]
    fn to_listener(&self, _conf: &ServerConf) -> io::Result<Box<dyn ToTokioListener + Send>> {
        debug!("binding socket to {}", self);
        Ok(Box::new(::std::os::unix::net::UnixListener::bind(&self.0)?))
    }

    #[cfg(not(unix))]
    fn to_listener(&self, _conf: &ServerConf) -> io::Result<Box<ToTokioListener + Send>> {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "cannot use unix sockets on non-unix",
        ))
    }

    fn cleanup(&self) {
        if self.0.exists() {
            fs::remove_file(&self.0).expect("removing socket during shutdown");
        }
    }
}

#[cfg(unix)]
impl ToTokioListener for ::std::os::unix::net::UnixListener {
    fn to_tokio_listener(self: Box<Self>, handle: &Handle) -> Box<dyn ToServerStream> {
        handle.enter(|| Box::new(UnixListener::from_std(*self).unwrap()))
    }

    fn local_addr(&self) -> io::Result<AnySocketAddr> {
        let addr = self.local_addr().unwrap();
        let path = addr.as_pathname().unwrap();
        Ok(AnySocketAddr::Unix(SocketAddrUnix::from(path)))
    }
}

#[cfg(unix)]
impl ToServerStream for UnixListener {
    fn incoming(
        self: Box<Self>,
    ) -> Pin<
        Box<dyn Stream<Item = io::Result<(Pin<Box<dyn StreamItem + Send>>, AnySocketAddr)>> + Send>,
    > {
        let unix_listener = *self;

        let stream = stream::unfold(unix_listener, |mut unix_listener_listener| async {
            let r = match unix_listener_listener.accept().await {
                Ok((socket, addr)) => Ok((
                    Box::pin(socket) as Pin<Box<dyn StreamItem + Send>>,
                    AnySocketAddr::Unix(addr.into()),
                )),
                Err(e) => Err(e),
            };
            Some((r, unix_listener_listener))
        });

        let stream = assert_send_stream::<
            io::Result<(Pin<Box<dyn StreamItem + Send>>, AnySocketAddr)>,
            _,
        >(stream);

        Box::pin(stream)
    }
}

impl ToClientStream for SocketAddrUnix {
    #[cfg(unix)]
    fn connect(
        &self,
        handle: &Handle,
    ) -> Pin<Box<dyn Future<Output = io::Result<Pin<Box<dyn StreamItem + Send>>>> + Send>> {
        // TODO: async connect
        let stream = match std::os::unix::net::UnixStream::connect(&self.0) {
            Ok(stream) => stream,
            Err(e) => return Box::pin(async { Err(e) }),
        };
        match handle.enter(|| UnixStream::from_std(stream)) {
            Ok(stream) => {
                Box::pin(async { Ok(Box::pin(stream) as Pin<Box<dyn StreamItem + Send>>) })
            }
            Err(e) => return Box::pin(async { Err(e) }),
        }
    }

    #[cfg(not(unix))]
    fn connect(
        &self,
        _handle: &Handle,
    ) -> Pin<Box<dyn Future<Output = io::Result<Box<dyn StreamItem + Send>>> + Send>> {
        use futures::future;
        Box::pin(future::err(io::Error::new(
            io::ErrorKind::Other,
            "cannot use unix sockets on non-unix",
        )))
    }

    fn socket_addr(&self) -> AnySocketAddr {
        AnySocketAddr::Unix(self.clone())
    }
}

#[cfg(unix)]
impl StreamItem for UnixStream {
    fn is_tcp(&self) -> bool {
        false
    }

    fn set_nodelay(&self, _no_delay: bool) -> io::Result<()> {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Cannot set nodelay on unix domain socket",
        ))
    }
}
<commit_msg>Fix compilation on Windows<commit_after>use std::fs;
use std::io;
use std::path::Path;

#[cfg(unix)]
use tokio::net::UnixListener;
#[cfg(unix)]
use tokio::net::UnixStream;

use futures::stream;

use futures::stream::Stream;
use futures::Future;

use crate::assert_types::assert_send_stream;
use crate::socket::AnySocketAddr;
use crate::socket::StreamItem;
use crate::socket::ToClientStream;
use crate::socket::ToServerStream;
use crate::socket::ToSocketListener;
use crate::socket::ToTokioListener;
use crate::ServerConf;
use std::fmt;
#[cfg(unix)]
use std::os::unix::net::SocketAddr;
use std::path::PathBuf;
use std::pin::Pin;
use tokio::runtime::Handle;

#[derive(Debug, Clone, PartialEq)]
pub struct SocketAddrUnix(pub(crate) PathBuf);

impl From<PathBuf> for SocketAddrUnix {
    fn from(p: PathBuf) -> Self {
        SocketAddrUnix(p)
    }
}

impl From<&Path> for SocketAddrUnix {
    fn from(p: &Path) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl From<&str> for SocketAddrUnix {
    fn from(p: &str) -> Self {
        SocketAddrUnix(p.into())
    }
}

impl From<String> for SocketAddrUnix {
    fn from(p: String) -> Self {
        SocketAddrUnix(p.into())
    }
}

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

#[cfg(unix)]
impl From<SocketAddr> for SocketAddrUnix {
    fn from(s: SocketAddr) -> Self {
        // can be unnamed
        SocketAddrUnix(s.as_pathname().unwrap_or(Path::new("")).to_owned())
    }
}

impl ToSocketListener for SocketAddrUnix {
    #[cfg(unix)]
    fn to_listener(&self, _conf: &ServerConf) -> io::Result<Box<dyn ToTokioListener + Send>> {
        debug!("binding socket to {}", self);
        Ok(Box::new(::std::os::unix::net::UnixListener::bind(&self.0)?))
    }

    #[cfg(not(unix))]
    fn to_listener(&self, _conf: &ServerConf) -> io::Result<Box<ToTokioListener + Send>> {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "cannot use unix sockets on non-unix",
        ))
    }

    fn cleanup(&self) {
        if self.0.exists() {
            fs::remove_file(&self.0).expect("removing socket during shutdown");
        }
    }
}

#[cfg(unix)]
impl ToTokioListener for ::std::os::unix::net::UnixListener {
    fn to_tokio_listener(self: Box<Self>, handle: &Handle) -> Box<dyn ToServerStream> {
        handle.enter(|| Box::new(UnixListener::from_std(*self).unwrap()))
    }

    fn local_addr(&self) -> io::Result<AnySocketAddr> {
        let addr = self.local_addr().unwrap();
        let path = addr.as_pathname().unwrap();
        Ok(AnySocketAddr::Unix(SocketAddrUnix::from(path)))
    }
}

#[cfg(unix)]
impl ToServerStream for UnixListener {
    fn incoming(
        self: Box<Self>,
    ) -> Pin<
        Box<dyn Stream<Item = io::Result<(Pin<Box<dyn StreamItem + Send>>, AnySocketAddr)>> + Send>,
    > {
        let unix_listener = *self;

        let stream = stream::unfold(unix_listener, |mut unix_listener_listener| async {
            let r = match unix_listener_listener.accept().await {
                Ok((socket, addr)) => Ok((
                    Box::pin(socket) as Pin<Box<dyn StreamItem + Send>>,
                    AnySocketAddr::Unix(addr.into()),
                )),
                Err(e) => Err(e),
            };
            Some((r, unix_listener_listener))
        });

        let stream = assert_send_stream::<
            io::Result<(Pin<Box<dyn StreamItem + Send>>, AnySocketAddr)>,
            _,
        >(stream);

        Box::pin(stream)
    }
}

impl ToClientStream for SocketAddrUnix {
    #[cfg(unix)]
    fn connect(
        &self,
        handle: &Handle,
    ) -> Pin<Box<dyn Future<Output = io::Result<Pin<Box<dyn StreamItem + Send>>>> + Send>> {
        // TODO: async connect
        let stream = match std::os::unix::net::UnixStream::connect(&self.0) {
            Ok(stream) => stream,
            Err(e) => return Box::pin(async { Err(e) }),
        };
        match handle.enter(|| UnixStream::from_std(stream)) {
            Ok(stream) => {
                Box::pin(async { Ok(Box::pin(stream) as Pin<Box<dyn StreamItem + Send>>) })
            }
            Err(e) => return Box::pin(async { Err(e) }),
        }
    }

    #[cfg(not(unix))]
    fn connect(
        &self,
        _handle: &Handle,
    ) -> Pin<Box<dyn Future<Output = io::Result<Pin<Box<dyn StreamItem + Send>>>> + Send>> {
        use futures::future;
        Box::pin(future::err(io::Error::new(
            io::ErrorKind::Other,
            "cannot use unix sockets on non-unix",
        )))
    }

    fn socket_addr(&self) -> AnySocketAddr {
        AnySocketAddr::Unix(self.clone())
    }
}

#[cfg(unix)]
impl StreamItem for UnixStream {
    fn is_tcp(&self) -> bool {
        false
    }

    fn set_nodelay(&self, _no_delay: bool) -> io::Result<()> {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Cannot set nodelay on unix domain socket",
        ))
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use rusqlite::Connection;
use db_variable_name;
use db_job;
use db_fs_file;
use serde_yaml;
use std::collections::HashSet;

fn job_provide_list_by_job(conn: &Connection) -> Vec<db_variable_name::VariableName> {
    let mut items = Vec::<db_variable_name::VariableName>::new();
    let provide_list_prep_rc = conn.prepare(
        "SELECT DISTINCT
            VARIABLE_NAME.id,
            VARIABLE_NAME.name
            FROM JOBPROVIDE , VARIABLE_NAME
        WHERE
            VARIABLE_NAME.id = JOBPROVIDE.fk_variable
            order by VARIABLE_NAME.name",
    );
    if provide_list_prep_rc.is_err() {
        error!("SQL issue in job_provide_list");
        return items;
    }
    let mut provide_list_prep = provide_list_prep_rc.unwrap();

    let result_row = provide_list_prep.query(&[]);
    let mut rox = result_row.unwrap();

    while let Some(row_query) = rox.next() {
        let row = row_query.unwrap();
        let bill = db_variable_name::VariableName {
            id: row.get(0),
            name: row.get(1),
        };
        debug!("bill:{}", bill.id);
        items.push(bill);
    }
    return items;
}

fn job_depend_list_by_job(conn: &Connection) -> Vec<db_variable_name::VariableName> {
    let mut items = Vec::<db_variable_name::VariableName>::new();
    let provide_list_prep_rc = conn.prepare(
        "SELECT DISTINCT
            VARIABLE_NAME.id,
            VARIABLE_NAME.name
            FROM JOBDEPEND , VARIABLE_NAME
        WHERE
            VARIABLE_NAME.id = JOBDEPEND.fk_variable
            order by VARIABLE_NAME.name",
    );
    if provide_list_prep_rc.is_err() {
        error!("SQL issue in job_provide_list");
        return items;
    }
    let mut provide_list_prep = provide_list_prep_rc.unwrap();

    let result_row = provide_list_prep.query(&[]);
    let mut rox = result_row.unwrap();

    while let Some(row_query) = rox.next() {
        let row = row_query.unwrap();
        let bill = db_variable_name::VariableName {
            id: row.get(0),
            name: row.get(1),
        };
        debug!("bill:{}", bill.id);
        items.push(bill);
    }
    return items;
}

fn job_targets_list_by_job(conn: &Connection) -> Vec<db_variable_name::VariableName> {
    let mut items = Vec::<db_variable_name::VariableName>::new();

    let mut hs_depend: HashSet<i32> = HashSet::new();
    let list_dep = job_depend_list_by_job(&conn);
    for item in list_dep {
        hs_depend.insert(item.id);
    }
    for item in job_provide_list_by_job(&conn) {
        let foo = hs_depend.contains(&item.id);
        if foo == false {
            items.push(item)
        }
    }
    return items;
}

fn list_job(conn: &Connection, fk_variable_name: &i32) -> Vec<db_job::Job> {
    let mut items = Vec::<db_job::Job>::new();
    let provide_list_prep_rc = conn.prepare(
        "SELECT DISTINCT
            JOB.id,
            JOB.name,
            JOB.fk_file
            FROM JOB, JOBPROVIDE , VARIABLE_NAME
        WHERE
            JOB.id = JOBPROVIDE.fk_job
            AND
            VARIABLE_NAME.id = JOBPROVIDE.fk_variable
            AND
            VARIABLE_NAME.id = ?1
            order by JOB.name",
    );
    if provide_list_prep_rc.is_err() {
        error!("SQL issue in job_provide_list");
        return items;
    }
    let mut provide_list_prep = provide_list_prep_rc.unwrap();

    let result_row = provide_list_prep.query(&[fk_variable_name]);
    let mut rox = result_row.unwrap();

    while let Some(row_query) = rox.next() {
        let row = row_query.unwrap();
        let bill = db_job::Job {
            id: row.get(0),
            name: row.get(1),
            fk_file: row.get(2),
        };
        debug!("bill:{}", bill.id);
        items.push(bill);
    }
    return items;
}

fn list_file(conn: &Connection, fk_variable_name: &i32) -> Vec<db_fs_file::FsFile> {
    let mut items = Vec::<db_fs_file::FsFile>::new();
    let provide_list_prep_rc = conn.prepare(
        "SELECT DISTINCT
            FS_FILE.id,
            FS_FILE.fk_fs_dir,
            FS_FILE.name
        FROM
            FS_FILE
        WHERE
            FS_FILE.id = ?1
            order by FS_FILE.name",
    );
    if provide_list_prep_rc.is_err() {
        error!("SQL issue in job_provide_list");
        return items;
    }
    let mut provide_list_prep = provide_list_prep_rc.unwrap();

    let result_row = provide_list_prep.query(&[fk_variable_name]);
    let mut rox = result_row.unwrap();

    while let Some(row_query) = rox.next() {
        let row = row_query.unwrap();
        let bill = db_fs_file::FsFile {
            id: row.get(0),
            fk_fs_dir: row.get(1),
            name: row.get(2),
        };
        debug!("bill:{}", bill.id);
        items.push(bill);
    }
    return items;
}

fn shared_foo(conn: &Connection, variables: &Vec<db_variable_name::VariableName>) -> String {
    let mut map = BTreeMap::new();
    for var_name in variables {
        let mut v_new = Vec::<BTreeMap<&str, String>>::new();
        let doop = list_job(&conn, &var_name.id);
        for item in doop {
            let mut map2 = BTreeMap::new();
            map2.insert("name", item.name.to_string());
            let woop = list_file(&conn, &item.fk_file);
            for op in woop {
                map2.insert("file_name", op.name.to_string());
            }
            v_new.push(map2);
        }
        map.insert(var_name.name.to_string(), v_new);
    }
    return serde_yaml::to_string(&map).unwrap();
}

pub fn process_list_provides(conn: &Connection) {
    let henry = job_provide_list_by_job(&conn);
    println!("{}", shared_foo(&conn, &henry));
}

pub fn process_list_targets(conn: &Connection) {
    let henry = job_targets_list_by_job(&conn);
    println!("{}", shared_foo(&conn, &henry));
}
<commit_msg>Beutify the rust code<commit_after>use db_fs_file;
use db_job;
use db_variable_name;
use rusqlite::Connection;
use serde_yaml;
use std::collections::BTreeMap;
use std::collections::HashSet;

fn job_provide_list_by_job(conn: &Connection) -> Vec<db_variable_name::VariableName> {
    let mut items = Vec::<db_variable_name::VariableName>::new();
    let provide_list_prep_rc = conn.prepare(
        "SELECT DISTINCT
            VARIABLE_NAME.id,
            VARIABLE_NAME.name
            FROM JOBPROVIDE , VARIABLE_NAME
        WHERE
            VARIABLE_NAME.id = JOBPROVIDE.fk_variable
            order by VARIABLE_NAME.name",
    );
    if provide_list_prep_rc.is_err() {
        error!("SQL issue in job_provide_list");
        return items;
    }
    let mut provide_list_prep = provide_list_prep_rc.unwrap();

    let result_row = provide_list_prep.query(&[]);
    let mut rox = result_row.unwrap();

    while let Some(row_query) = rox.next() {
        let row = row_query.unwrap();
        let bill = db_variable_name::VariableName {
            id: row.get(0),
            name: row.get(1),
        };
        debug!("bill:{}", bill.id);
        items.push(bill);
    }
    return items;
}

fn job_depend_list_by_job(conn: &Connection) -> Vec<db_variable_name::VariableName> {
    let mut items = Vec::<db_variable_name::VariableName>::new();
    let provide_list_prep_rc = conn.prepare(
        "SELECT DISTINCT
            VARIABLE_NAME.id,
            VARIABLE_NAME.name
            FROM JOBDEPEND , VARIABLE_NAME
        WHERE
            VARIABLE_NAME.id = JOBDEPEND.fk_variable
            order by VARIABLE_NAME.name",
    );
    if provide_list_prep_rc.is_err() {
        error!("SQL issue in job_provide_list");
        return items;
    }
    let mut provide_list_prep = provide_list_prep_rc.unwrap();

    let result_row = provide_list_prep.query(&[]);
    let mut rox = result_row.unwrap();

    while let Some(row_query) = rox.next() {
        let row = row_query.unwrap();
        let bill = db_variable_name::VariableName {
            id: row.get(0),
            name: row.get(1),
        };
        debug!("bill:{}", bill.id);
        items.push(bill);
    }
    return items;
}

fn job_targets_list_by_job(conn: &Connection) -> Vec<db_variable_name::VariableName> {
    let mut items = Vec::<db_variable_name::VariableName>::new();

    let mut hs_depend: HashSet<i32> = HashSet::new();
    let list_dep = job_depend_list_by_job(&conn);
    for item in list_dep {
        hs_depend.insert(item.id);
    }
    for item in job_provide_list_by_job(&conn) {
        let foo = hs_depend.contains(&item.id);
        if foo == false {
            items.push(item)
        }
    }
    return items;
}

fn list_job(conn: &Connection, fk_variable_name: &i32) -> Vec<db_job::Job> {
    let mut items = Vec::<db_job::Job>::new();
    let provide_list_prep_rc = conn.prepare(
        "SELECT DISTINCT
            JOB.id,
            JOB.name,
            JOB.fk_file
            FROM JOB, JOBPROVIDE , VARIABLE_NAME
        WHERE
            JOB.id = JOBPROVIDE.fk_job
            AND
            VARIABLE_NAME.id = JOBPROVIDE.fk_variable
            AND
            VARIABLE_NAME.id = ?1
            order by JOB.name",
    );
    if provide_list_prep_rc.is_err() {
        error!("SQL issue in job_provide_list");
        return items;
    }
    let mut provide_list_prep = provide_list_prep_rc.unwrap();

    let result_row = provide_list_prep.query(&[fk_variable_name]);
    let mut rox = result_row.unwrap();

    while let Some(row_query) = rox.next() {
        let row = row_query.unwrap();
        let bill = db_job::Job {
            id: row.get(0),
            name: row.get(1),
            fk_file: row.get(2),
        };
        debug!("bill:{}", bill.id);
        items.push(bill);
    }
    return items;
}

fn list_file(conn: &Connection, fk_variable_name: &i32) -> Vec<db_fs_file::FsFile> {
    let mut items = Vec::<db_fs_file::FsFile>::new();
    let provide_list_prep_rc = conn.prepare(
        "SELECT DISTINCT
            FS_FILE.id,
            FS_FILE.fk_fs_dir,
            FS_FILE.name
        FROM
            FS_FILE
        WHERE
            FS_FILE.id = ?1
            order by FS_FILE.name",
    );
    if provide_list_prep_rc.is_err() {
        error!("SQL issue in job_provide_list");
        return items;
    }
    let mut provide_list_prep = provide_list_prep_rc.unwrap();

    let result_row = provide_list_prep.query(&[fk_variable_name]);
    let mut rox = result_row.unwrap();

    while let Some(row_query) = rox.next() {
        let row = row_query.unwrap();
        let bill = db_fs_file::FsFile {
            id: row.get(0),
            fk_fs_dir: row.get(1),
            name: row.get(2),
        };
        debug!("bill:{}", bill.id);
        items.push(bill);
    }
    return items;
}

fn shared_foo(conn: &Connection, variables: &Vec<db_variable_name::VariableName>) -> String {
    let mut map = BTreeMap::new();
    for var_name in variables {
        let mut v_new = Vec::<BTreeMap<&str, String>>::new();
        let doop = list_job(&conn, &var_name.id);
        for item in doop {
            let mut map2 = BTreeMap::new();
            map2.insert("name", item.name.to_string());
            let woop = list_file(&conn, &item.fk_file);
            for op in woop {
                map2.insert("file_name", op.name.to_string());
            }
            v_new.push(map2);
        }
        map.insert(var_name.name.to_string(), v_new);
    }
    return serde_yaml::to_string(&map).unwrap();
}

pub fn process_list_provides(conn: &Connection) {
    let henry = job_provide_list_by_job(&conn);
    println!("{}", shared_foo(&conn, &henry));
}

pub fn process_list_targets(conn: &Connection) {
    let henry = job_targets_list_by_job(&conn);
    println!("{}", shared_foo(&conn, &henry));
}
<|endoftext|>


<commit_before>use std::vec::Vec;
use std::string::String;

struct Compiler {
    pub lines: Vec<String>,
    pub instructions: Vec<String>,
}

impl Compiler {
    pub fn new() -> Self {
        Compiler {
            lines: Vec::new(),
            instructions: Vec::new(),
        }
    }

    pub fn parse(&mut self, assembly: &str) {
        self.split_lines(assembly);
        self.strip_comments();
    }

    fn strip_comments(&mut self) {
        let mut lines = self.lines.iter();
        while let Some(line) = lines.next() {
            let trimmed_line = line.trim();
            if !trimmed_line.is_empty() && !trimmed_line.starts_with(";") {
                let instruction = match trimmed_line.find(';') {
                    Some(index) => trimmed_line.split_at(index).0,
                    None => trimmed_line,
                };
                self.instructions.push(instruction.trim().to_string());
            }
        }
    }

    fn split_lines(&mut self, assembly: &str) {
        let mut line = String::new();
        let mut chars = assembly.chars();

        while let Some(c) = chars.next() {
            match c {
                // Line Feed | Vertical Tab | Form Feed | Next Line | Line/Paragraph Separator
                '\u{000A}' | '\u{000B}' | '\u{000C}' | '\u{0085}' | '\u{2028}' | '\u{2029}' => {
                    self.lines.push(line);
                    line = String::new();
                }

                // Carriage Return
                '\u{000D}' => {
                    self.lines.push(line);
                    line = String::new();

                    // Carriage Return + Line Feed
                    match chars.next() {
                        Some(n) => {
                            if n != '\u{000A}' {
                                line.push(n);
                            }
                        }
                        None => {}
                    }
                }

                _ => {
                    line.push(c);
                }
            }
        }

        if !line.is_empty() {
            self.lines.push(line);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Compiler;

    #[test]
    fn it_splits_lines_by_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_vertical_tab() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0B0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_form_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0C0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_next_line() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{0085}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_line_separator() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{2028}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_paragraph_separator() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{2029}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_ignors_trailing_separators() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0\r\n");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_strips_single_line_comments() {
        let mut compiler = Compiler::new();
        compiler.parse("; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_single_line_comments_starting_with_spaces() {
        let mut compiler = Compiler::new();
        compiler.parse(" ; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_single_line_comments_starting_with_tabs() {
        let mut compiler = Compiler::new();
        compiler.parse("\t; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_inline_comments() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_strips_inline_comments_starting_with_spaces() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0 ; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_strips_inline_comments_starting_with_tabs() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\t; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_trims_spaces_from_instructions() {
        let mut compiler = Compiler::new();
        compiler.parse(" 0 0 0 0 ");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_trims_tabs_from_instructions() {
        let mut compiler = Compiler::new();
        compiler.parse("\t0 0 0 0\t");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }
}
<commit_msg>Compiles labels into an address map.<commit_after>use std::vec::Vec;
use std::string::String;
use std::collections::HashMap;

struct Compiler {
    pub lines: Vec<String>,
    pub instructions: Vec<String>,
    pub labels: HashMap<String, u32>,
}

impl Compiler {
    pub fn new() -> Self {
        Compiler {
            lines: Vec::new(),
            instructions: Vec::new(),
            labels: HashMap::new(),
        }
    }

    pub fn parse(&mut self, assembly: &str) {
        self.split_lines(assembly);
        self.strip_comments();
        self.compile_labels();
    }

    fn compile_labels(&mut self) {
        let mut instructions = self.instructions.iter();
        let mut address = 0;

        while let Some(instruction) = instructions.next() {
            match instruction.find(':') {
                Some(index) => {
                    self.labels.insert(instruction.split_at(index).0.to_string(), address);
                }
                None => {
                    address += 4;
                }
            }
        }
    }

    fn strip_comments(&mut self) {
        let mut lines = self.lines.iter();
        while let Some(line) = lines.next() {
            let trimmed_line = line.trim();
            if !trimmed_line.is_empty() && !trimmed_line.starts_with(";") {
                let instruction = match trimmed_line.find(';') {
                    Some(index) => trimmed_line.split_at(index).0,
                    None => trimmed_line,
                };
                self.instructions.push(instruction.trim().to_string());
            }
        }
    }

    fn split_lines(&mut self, assembly: &str) {
        let mut line = String::new();
        let mut chars = assembly.chars();

        while let Some(c) = chars.next() {
            match c {
                // Line Feed | Vertical Tab | Form Feed | Next Line | Line/Paragraph Separator
                '\u{000A}' | '\u{000B}' | '\u{000C}' | '\u{0085}' | '\u{2028}' | '\u{2029}' => {
                    self.lines.push(line);
                    line = String::new();
                }

                // Carriage Return
                '\u{000D}' => {
                    self.lines.push(line);
                    line = String::new();

                    // Carriage Return + Line Feed
                    match chars.next() {
                        Some(n) => {
                            if n != '\u{000A}' {
                                line.push(n);
                            }
                        }
                        None => {}
                    }
                }

                _ => {
                    line.push(c);
                }
            }
        }

        if !line.is_empty() {
            self.lines.push(line);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Compiler;
    use std::collections::HashMap;

    #[test]
    fn it_splits_lines_by_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_vertical_tab() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0B0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_form_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0C0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_next_line() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{0085}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_line_separator() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{2028}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_paragraph_separator() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{2029}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_ignors_trailing_separators() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0\r\n");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_strips_single_line_comments() {
        let mut compiler = Compiler::new();
        compiler.parse("; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_single_line_comments_starting_with_spaces() {
        let mut compiler = Compiler::new();
        compiler.parse(" ; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_single_line_comments_starting_with_tabs() {
        let mut compiler = Compiler::new();
        compiler.parse("\t; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_inline_comments() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_strips_inline_comments_starting_with_spaces() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0 ; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_strips_inline_comments_starting_with_tabs() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\t; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_trims_spaces_from_instructions() {
        let mut compiler = Compiler::new();
        compiler.parse(" 0 0 0 0 ");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_trims_tabs_from_instructions() {
        let mut compiler = Compiler::new();
        compiler.parse("\t0 0 0 0\t");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_compiles_addresses_for_labels() {
        let mut compiler = Compiler::new();
        compiler.parse("first:\nsecond:\n0 0 0 0\nthird:");

        let mut labels = HashMap::new();
        labels.insert("first".to_string(), 0);
        labels.insert("second".to_string(), 0);
        labels.insert("third".to_string(), 4);

        assert_eq!(compiler.labels, labels);
    }

    #[test]
    fn it_lets_the_last_label_win() {
        let mut compiler = Compiler::new();
        compiler.parse("label:\n0 0 0 0\nlabel:");

        let mut labels = HashMap::new();
        labels.insert("label".to_string(), 4);

        assert_eq!(compiler.labels, labels);
    }

    #[test]
    fn it_ignores_trailing_label_characters() {
        let mut compiler = Compiler::new();
        compiler.parse("label:with bits\n0 0 0 0\nlabel:with bytes");

        let mut labels = HashMap::new();
        labels.insert("label".to_string(), 4);

        assert_eq!(compiler.labels, labels);
    }
}
<|endoftext|>


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

#[macro_use]
extern crate gj;
extern crate gjio;

use std::net::ToSocketAddrs;
use gjio::{AsyncRead, AsyncWrite};
use gj::{EventLoop, Promise};

fn forward<R,W,B>(mut src: R, mut dst: W, buf: B) -> Promise<(R, W), ::std::io::Error>
    where R: AsyncRead + 'static, W: AsyncWrite + 'static, B: AsMut<[u8]> + AsRef<[u8]> + 'static
{
    src.try_read(buf, 1).then(move |(buf, n)| {
        if n == 0 { // EOF
            Promise::ok((src, dst))
        } else {
            dst.write(gjio::BufferPrefix::new(buf, n)).then(move |prefix| {
                forward(src, dst, prefix.buf)
            })
        }
    })
}

fn accept_loop(receiver: gjio::SocketListener,
               outbound_addr: gjio::SocketAddress,
               timer: gjio::Timer,
               mut task_set: gj::TaskSet<(), ::std::io::Error>)
               -> Promise<(), ::std::io::Error>
{
    receiver.accept().then(move |src_stream| {
        println!("handling connection");

        timer.timeout_after(::std::time::Duration::from_secs(3), outbound_addr.connect())
           .then_else(move |r| match r {
               Ok(dst_stream) =>  {
                   let task1 = forward(src_stream.clone(), dst_stream.clone(), vec![0; 1024])
                       .map(|(_src, mut dst)| dst.shutdown(::std::net::Shutdown::Write));
                   let task2 =
                       forward(dst_stream.clone(), src_stream.clone(), vec![0; 1024]).map(|_| Ok(()));
                   task_set.add(task1);
                   task_set.add(task2);
                   accept_loop(receiver, outbound_addr, timer, task_set)
               }
               Err(e) => {
                   println!("failed to connect: {}", e);
                   Promise::err(e.into())
               }
           })
    })
}

pub struct Reporter;

impl gj::TaskReaper<(), ::std::io::Error> for Reporter {
    fn task_failed(&mut self, error: ::std::io::Error) {
        println!("Task failed: {}", error);
    }
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} <LISTEN_ADDR> <CONNECT_ADDR>", args[0]);
        return;
    }

    EventLoop::top_level(|wait_scope| -> Result<(), ::std::io::Error> {
        let mut event_port = try!(gjio::EventPort::new());
        let network = event_port.get_network();
        let addr = try!(args[1].to_socket_addrs()).next().expect("could not parse address");
        let mut address = network.get_tcp_address(addr);
        let listener = try!(address.listen());

        let outbound_addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let outbound_address = network.get_tcp_address(outbound_addr);
        accept_loop(listener, outbound_address, event_port.get_timer(),
                    gj::TaskSet::new(Box::new(Reporter))).wait(wait_scope, &mut event_port)
    }).expect("top level");
}
<commit_msg>style<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#[macro_use]
extern crate gj;
extern crate gjio;

use std::net::ToSocketAddrs;
use gjio::{AsyncRead, AsyncWrite};
use gj::{EventLoop, Promise};

fn forward<R,W,B>(mut src: R, mut dst: W, buf: B) -> Promise<(R, W), ::std::io::Error>
    where R: AsyncRead + 'static, W: AsyncWrite + 'static, B: AsMut<[u8]> + AsRef<[u8]> + 'static
{
    src.try_read(buf, 1).then(move |(buf, n)| {
        if n == 0 { // EOF
            Promise::ok((src, dst))
        } else {
            dst.write(gjio::BufferPrefix::new(buf, n)).then(move |prefix| {
                forward(src, dst, prefix.buf)
            })
        }
    })
}

fn accept_loop(receiver: gjio::SocketListener,
               outbound_addr: gjio::SocketAddress,
               timer: gjio::Timer,
               mut task_set: gj::TaskSet<(), ::std::io::Error>)
               -> Promise<(), ::std::io::Error>
{
    receiver.accept().then(move |src_stream| {
        println!("handling connection");

        timer.timeout_after(::std::time::Duration::from_secs(3), outbound_addr.connect())
           .then_else(move |r| match r {
               Ok(dst_stream) =>  {
                   task_set.add(
                       forward(src_stream.clone(), dst_stream.clone(), vec![0; 1024])
                           .map(|(_src, mut dst)| dst.shutdown(::std::net::Shutdown::Write)));
                   task_set.add(
                       forward(dst_stream.clone(), src_stream.clone(), vec![0; 1024])
                           .map(|_| Ok(())));
                   accept_loop(receiver, outbound_addr, timer, task_set)
               }
               Err(e) => {
                   println!("failed to connect: {}", e);
                   Promise::err(e.into())
               }
           })
    })
}

pub struct Reporter;

impl gj::TaskReaper<(), ::std::io::Error> for Reporter {
    fn task_failed(&mut self, error: ::std::io::Error) {
        println!("Task failed: {}", error);
    }
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} <LISTEN_ADDR> <CONNECT_ADDR>", args[0]);
        return;
    }

    EventLoop::top_level(|wait_scope| -> Result<(), ::std::io::Error> {
        let mut event_port = try!(gjio::EventPort::new());
        let network = event_port.get_network();
        let addr = try!(args[1].to_socket_addrs()).next().expect("could not parse address");
        let mut address = network.get_tcp_address(addr);
        let listener = try!(address.listen());

        let outbound_addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let outbound_address = network.get_tcp_address(outbound_addr);
        accept_loop(listener, outbound_address, event_port.get_timer(),
                    gj::TaskSet::new(Box::new(Reporter))).wait(wait_scope, &mut event_port)
    }).expect("top level");
}
<|endoftext|>