<commit_before>mod database;
pub(crate) mod s3;

pub(crate) use self::database::DatabaseBackend;
pub(crate) use self::s3::S3Backend;
#[cfg(test)]
pub(crate) use self::s3::TIME_FMT;
use failure::Error;
use time::Timespec;

use failure::err_msg;
use postgres::{transaction::Transaction, Connection};
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct Blob {
    pub(crate) path: String,
    pub(crate) mime: String,
    pub(crate) date_updated: Timespec,
    pub(crate) content: Vec<u8>,
}

fn get_file_list_from_dir<P: AsRef<Path>>(path: P, files: &mut Vec<PathBuf>) -> Result<(), Error> {
    let path = path.as_ref();

    for file in path.read_dir()? {
        let file = file?;

        if file.file_type()?.is_file() {
            files.push(file.path());
        } else if file.file_type()?.is_dir() {
            get_file_list_from_dir(file.path(), files)?;
        }
    }

    Ok(())
}

pub fn get_file_list<P: AsRef<Path>>(path: P) -> Result<Vec<PathBuf>, Error> {
    let path = path.as_ref();
    let mut files = Vec::new();

    if !path.exists() {
        return Err(err_msg("File not found"));
    } else if path.is_file() {
        files.push(PathBuf::from(path.file_name().unwrap()));
    } else if path.is_dir() {
        get_file_list_from_dir(path, &mut files)?;
        for file_path in &mut files {
            // We want the paths in this list to not be {path}/bar.txt but just bar.txt
            *file_path = PathBuf::from(file_path.strip_prefix(path).unwrap());
        }
    }

    Ok(files)
}

pub(crate) enum Storage<'a> {
    Database(DatabaseBackend<'a>),
    S3(S3Backend<'a>),
}

impl<'a> Storage<'a> {
    pub(crate) fn new(conn: &'a Connection) -> Self {
        if let Some(c) = s3::s3_client() {
            Storage::from(S3Backend::new(c, s3::S3_BUCKET_NAME))
        } else {
            DatabaseBackend::new(conn).into()
        }
    }
    pub(crate) fn get(&self, path: &str) -> Result<Blob, Error> {
        match self {
            Self::Database(db) => db.get(path),
            Self::S3(s3) => s3.get(path),
        }
    }

    fn store_batch(&mut self, batch: &[Blob], trans: &Transaction) -> Result<(), Error> {
        match self {
            Self::Database(db) => db.store_batch(batch, trans),
            Self::S3(s3) => s3.store_batch(batch),
        }
    }

    // Store all files in `root_dir` into the backend under `prefix`.
    //
    // If the environment is configured with S3 credentials, this will upload to S3;
    // otherwise, this will store files in the database.
    //
    // This returns a HashMap<filename, mime type>.
    pub(crate) fn store_all(
        &mut self,
        conn: &Connection,
        prefix: &str,
        root_dir: &Path,
    ) -> Result<HashMap<PathBuf, String>, Error> {
        const MAX_CONCURRENT_UPLOADS: usize = 1000;

        let trans = conn.transaction()?;
        let mut file_paths_and_mimes = HashMap::new();

        get_file_list(root_dir)?
            .into_iter()
            .filter_map(|file_path| {
                // Some files have insufficient permissions
                // (like .lock file created by cargo in documentation directory).
                // Skip these files.
                fs::File::open(root_dir.join(&file_path))
                    .ok()
                    .map(|file| (file_path, file))
            })
            .map(|(file_path, mut file)| {
                let mut content: Vec<u8> = Vec::new();
                file.read_to_end(&mut content)?;

                let bucket_path = Path::new(prefix).join(&file_path);

                #[cfg(windows)] // On windows, we need to normalize \\ to / so the route logic works
                let bucket_path = path_slash::PathBufExt::to_slash(&bucket_path).unwrap();
                #[cfg(not(windows))]
                let bucket_path = bucket_path.into_os_string().into_string().unwrap();

                let mime = detect_mime(&file_path)?;

                file_paths_and_mimes.insert(file_path, mime.to_string());
                Ok(Blob {
                    path: bucket_path,
                    mime: mime.to_string(),
                    content,
                    // this field is ignored by the backend
                    date_updated: Timespec::new(0, 0),
                })
            })
            .collect::<Result<Vec<_>, Error>>()?
            .chunks(MAX_CONCURRENT_UPLOADS)
            .try_for_each(|batch| self.store_batch(batch, &trans))?;

        trans.commit()?;
        Ok(file_paths_and_mimes)
    }
}

fn detect_mime(file_path: &Path) -> Result<&'static str, Error> {
    let mime = mime_guess::from_path(file_path)
        .first_raw()
        .map(|m| m)
        .unwrap_or("text/plain");
    Ok(match mime {
        "text/plain" | "text/troff" | "text/x-markdown" | "text/x-rust" | "text/x-toml" => {
            match file_path.extension().and_then(OsStr::to_str) {
                Some("md") => "text/markdown",
                Some("rs") => "text/rust",
                Some("markdown") => "text/markdown",
                Some("css") => "text/css",
                Some("toml") => "text/toml",
                Some("js") => "application/javascript",
                Some("json") => "application/json",
                _ => mime,
            }
        }
        "image/svg" => "image/svg+xml",
        _ => mime,
    })
}

impl<'a> From<DatabaseBackend<'a>> for Storage<'a> {
    fn from(db: DatabaseBackend<'a>) -> Self {
        Self::Database(db)
    }
}

impl<'a> From<S3Backend<'a>> for Storage<'a> {
    fn from(db: S3Backend<'a>) -> Self {
        Self::S3(db)
    }
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use super::*;
    use crate::test::wrapper;
    use std::env;

    #[test]
    fn test_uploads() {
        use std::fs;
        let dir = tempdir::TempDir::new("docs.rs-upload-test").unwrap();
        let files = ["Cargo.toml", "src/main.rs"];
        for &file in &files {
            let path = dir.path().join(file);
            if let Some(parent) = path.parent() {
                fs::create_dir_all(parent).unwrap();
            }
            fs::write(path, "data").expect("failed to write to file");
        }
        wrapper(|env| {
            let db = env.db();
            let conn = db.conn();
            let backend = Storage::Database(DatabaseBackend::new(&conn));
            let stored_files = backend.store_all(&conn, "rustdoc", dir.path()).unwrap();
            assert_eq!(stored_files.len(), files.len());
            for name in &files {
                let name = Path::new(name);
                assert!(stored_files.contains_key(name));
            }
            assert_eq!(
                stored_files.get(Path::new("Cargo.toml")).unwrap(),
                "text/toml"
            );
            assert_eq!(
                stored_files.get(Path::new("src/main.rs")).unwrap(),
                "text/rust"
            );

            let file = backend.get("rustdoc/Cargo.toml").unwrap();
            assert_eq!(file.content, b"data");
            assert_eq!(file.mime, "text/toml");
            assert_eq!(file.path, "rustdoc/Cargo.toml");

            let file = backend.get("rustdoc/src/main.rs").unwrap();
            assert_eq!(file.content, b"data");
            assert_eq!(file.mime, "text/rust");
            assert_eq!(file.path, "rustdoc/src/main.rs");
            Ok(())
        })
    }

    #[test]
    fn test_get_file_list() {
        let _ = env_logger::try_init();

        let files = get_file_list(env::current_dir().unwrap());
        assert!(files.is_ok());
        assert!(files.unwrap().len() > 0);

        let files = get_file_list(env::current_dir().unwrap().join("Cargo.toml")).unwrap();
        assert_eq!(files[0], std::path::Path::new("Cargo.toml"));
    }
    #[test]
    fn test_mime_types() {
        check_mime(".gitignore", "text/plain");
        check_mime("hello.toml", "text/toml");
        check_mime("hello.css", "text/css");
        check_mime("hello.js", "application/javascript");
        check_mime("hello.html", "text/html");
        check_mime("hello.hello.md", "text/markdown");
        check_mime("hello.markdown", "text/markdown");
        check_mime("hello.json", "application/json");
        check_mime("hello.txt", "text/plain");
        check_mime("file.rs", "text/rust");
        check_mime("important.svg", "image/svg+xml");
    }

    fn check_mime(path: &str, expected_mime: &str) {
        let detected_mime = detect_mime(Path::new(&path));
        let detected_mime = detected_mime.expect("no mime was given");
        assert_eq!(detected_mime, expected_mime);
    }
}
<commit_msg>Fix test failure<commit_after>mod database;
pub(crate) mod s3;

pub(crate) use self::database::DatabaseBackend;
pub(crate) use self::s3::S3Backend;
#[cfg(test)]
pub(crate) use self::s3::TIME_FMT;
use failure::Error;
use time::Timespec;

use failure::err_msg;
use postgres::{transaction::Transaction, Connection};
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct Blob {
    pub(crate) path: String,
    pub(crate) mime: String,
    pub(crate) date_updated: Timespec,
    pub(crate) content: Vec<u8>,
}

fn get_file_list_from_dir<P: AsRef<Path>>(path: P, files: &mut Vec<PathBuf>) -> Result<(), Error> {
    let path = path.as_ref();

    for file in path.read_dir()? {
        let file = file?;

        if file.file_type()?.is_file() {
            files.push(file.path());
        } else if file.file_type()?.is_dir() {
            get_file_list_from_dir(file.path(), files)?;
        }
    }

    Ok(())
}

pub fn get_file_list<P: AsRef<Path>>(path: P) -> Result<Vec<PathBuf>, Error> {
    let path = path.as_ref();
    let mut files = Vec::new();

    if !path.exists() {
        return Err(err_msg("File not found"));
    } else if path.is_file() {
        files.push(PathBuf::from(path.file_name().unwrap()));
    } else if path.is_dir() {
        get_file_list_from_dir(path, &mut files)?;
        for file_path in &mut files {
            // We want the paths in this list to not be {path}/bar.txt but just bar.txt
            *file_path = PathBuf::from(file_path.strip_prefix(path).unwrap());
        }
    }

    Ok(files)
}

pub(crate) enum Storage<'a> {
    Database(DatabaseBackend<'a>),
    S3(S3Backend<'a>),
}

impl<'a> Storage<'a> {
    pub(crate) fn new(conn: &'a Connection) -> Self {
        if let Some(c) = s3::s3_client() {
            Storage::from(S3Backend::new(c, s3::S3_BUCKET_NAME))
        } else {
            DatabaseBackend::new(conn).into()
        }
    }
    pub(crate) fn get(&self, path: &str) -> Result<Blob, Error> {
        match self {
            Self::Database(db) => db.get(path),
            Self::S3(s3) => s3.get(path),
        }
    }

    fn store_batch(&mut self, batch: &[Blob], trans: &Transaction) -> Result<(), Error> {
        match self {
            Self::Database(db) => db.store_batch(batch, trans),
            Self::S3(s3) => s3.store_batch(batch),
        }
    }

    // Store all files in `root_dir` into the backend under `prefix`.
    //
    // If the environment is configured with S3 credentials, this will upload to S3;
    // otherwise, this will store files in the database.
    //
    // This returns a HashMap<filename, mime type>.
    pub(crate) fn store_all(
        &mut self,
        conn: &Connection,
        prefix: &str,
        root_dir: &Path,
    ) -> Result<HashMap<PathBuf, String>, Error> {
        const MAX_CONCURRENT_UPLOADS: usize = 1000;

        let trans = conn.transaction()?;
        let mut file_paths_and_mimes = HashMap::new();

        get_file_list(root_dir)?
            .into_iter()
            .filter_map(|file_path| {
                // Some files have insufficient permissions
                // (like .lock file created by cargo in documentation directory).
                // Skip these files.
                fs::File::open(root_dir.join(&file_path))
                    .ok()
                    .map(|file| (file_path, file))
            })
            .map(|(file_path, mut file)| {
                let mut content: Vec<u8> = Vec::new();
                file.read_to_end(&mut content)?;

                let bucket_path = Path::new(prefix).join(&file_path);

                #[cfg(windows)] // On windows, we need to normalize \\ to / so the route logic works
                let bucket_path = path_slash::PathBufExt::to_slash(&bucket_path).unwrap();
                #[cfg(not(windows))]
                let bucket_path = bucket_path.into_os_string().into_string().unwrap();

                let mime = detect_mime(&file_path)?;

                file_paths_and_mimes.insert(file_path, mime.to_string());
                Ok(Blob {
                    path: bucket_path,
                    mime: mime.to_string(),
                    content,
                    // this field is ignored by the backend
                    date_updated: Timespec::new(0, 0),
                })
            })
            .collect::<Result<Vec<_>, Error>>()?
            .chunks(MAX_CONCURRENT_UPLOADS)
            .try_for_each(|batch| self.store_batch(batch, &trans))?;

        trans.commit()?;
        Ok(file_paths_and_mimes)
    }
}

fn detect_mime(file_path: &Path) -> Result<&'static str, Error> {
    let mime = mime_guess::from_path(file_path)
        .first_raw()
        .map(|m| m)
        .unwrap_or("text/plain");
    Ok(match mime {
        "text/plain" | "text/troff" | "text/x-markdown" | "text/x-rust" | "text/x-toml" => {
            match file_path.extension().and_then(OsStr::to_str) {
                Some("md") => "text/markdown",
                Some("rs") => "text/rust",
                Some("markdown") => "text/markdown",
                Some("css") => "text/css",
                Some("toml") => "text/toml",
                Some("js") => "application/javascript",
                Some("json") => "application/json",
                _ => mime,
            }
        }
        "image/svg" => "image/svg+xml",
        _ => mime,
    })
}

impl<'a> From<DatabaseBackend<'a>> for Storage<'a> {
    fn from(db: DatabaseBackend<'a>) -> Self {
        Self::Database(db)
    }
}

impl<'a> From<S3Backend<'a>> for Storage<'a> {
    fn from(db: S3Backend<'a>) -> Self {
        Self::S3(db)
    }
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use super::*;
    use crate::test::wrapper;
    use std::env;

    #[test]
    fn test_uploads() {
        use std::fs;
        let dir = tempdir::TempDir::new("docs.rs-upload-test").unwrap();
        let files = ["Cargo.toml", "src/main.rs"];
        for &file in &files {
            let path = dir.path().join(file);
            if let Some(parent) = path.parent() {
                fs::create_dir_all(parent).unwrap();
            }
            fs::write(path, "data").expect("failed to write to file");
        }
        wrapper(|env| {
            let db = env.db();
            let conn = db.conn();
            let mut backend = Storage::Database(DatabaseBackend::new(&conn));
            let stored_files = backend.store_all(&conn, "rustdoc", dir.path()).unwrap();
            assert_eq!(stored_files.len(), files.len());
            for name in &files {
                let name = Path::new(name);
                assert!(stored_files.contains_key(name));
            }
            assert_eq!(
                stored_files.get(Path::new("Cargo.toml")).unwrap(),
                "text/toml"
            );
            assert_eq!(
                stored_files.get(Path::new("src/main.rs")).unwrap(),
                "text/rust"
            );

            let file = backend.get("rustdoc/Cargo.toml").unwrap();
            assert_eq!(file.content, b"data");
            assert_eq!(file.mime, "text/toml");
            assert_eq!(file.path, "rustdoc/Cargo.toml");

            let file = backend.get("rustdoc/src/main.rs").unwrap();
            assert_eq!(file.content, b"data");
            assert_eq!(file.mime, "text/rust");
            assert_eq!(file.path, "rustdoc/src/main.rs");
            Ok(())
        })
    }

    #[test]
    fn test_get_file_list() {
        let _ = env_logger::try_init();

        let files = get_file_list(env::current_dir().unwrap());
        assert!(files.is_ok());
        assert!(files.unwrap().len() > 0);

        let files = get_file_list(env::current_dir().unwrap().join("Cargo.toml")).unwrap();
        assert_eq!(files[0], std::path::Path::new("Cargo.toml"));
    }
    #[test]
    fn test_mime_types() {
        check_mime(".gitignore", "text/plain");
        check_mime("hello.toml", "text/toml");
        check_mime("hello.css", "text/css");
        check_mime("hello.js", "application/javascript");
        check_mime("hello.html", "text/html");
        check_mime("hello.hello.md", "text/markdown");
        check_mime("hello.markdown", "text/markdown");
        check_mime("hello.json", "application/json");
        check_mime("hello.txt", "text/plain");
        check_mime("file.rs", "text/rust");
        check_mime("important.svg", "image/svg+xml");
    }

    fn check_mime(path: &str, expected_mime: &str) {
        let detected_mime = detect_mime(Path::new(&path));
        let detected_mime = detected_mime.expect("no mime was given");
        assert_eq!(detected_mime, expected_mime);
    }
}
<|endoftext|>


<commit_before>//!
//! This module provides syscall definitions and the necessary resources to parse incoming
//! syscalls

extern crate syscall;

pub use self::syscall::{data, error, flag, io, number, ptrace_event, scheme};

pub use self::driver::*;
pub use self::fs::*;
pub use self::futex::futex;
pub use self::privilege::*;
pub use self::process::*;
pub use self::time::*;
pub use self::validate::*;

use self::data::{SigAction, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags};
use self::number::*;

use crate::context::ContextId;
use crate::interrupt::InterruptStack;
use crate::scheme::{FileHandle, SchemeNamespace};

/// Debug
pub mod debug;

/// Driver syscalls
pub mod driver;

/// Filesystem syscalls
pub mod fs;

/// Fast userspace mutex
pub mod futex;

/// Privilege syscalls
pub mod privilege;

/// Process syscalls
pub mod process;

/// Time syscalls
pub mod time;

/// Validate input
pub mod validate;

/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> usize {
    #[inline(always)]
    fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> Result<usize> {
        //SYS_* is declared in kernel/syscall/src/number.rs
        match a & SYS_CLASS {
            SYS_CLASS_FILE => {
                let fd = FileHandle::from(b);
                match a & SYS_ARG {
                    SYS_ARG_SLICE => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
                    _ => match a {
                        SYS_CLOSE => close(fd),
                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
                        SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
                        SYS_FCNTL => fcntl(fd, c, d),
                        SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?),
                        SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?),
                        SYS_FUNMAP => funmap(b, c),
                        SYS_FMAP_OLD => {
                            {
                                let contexts = crate::context::contexts();
                                let current = contexts.current().unwrap();
                                let current = current.read();
                                let name = current.name.lock();
                                println!("{:?} using deprecated fmap(...) call", name);
                            }
                            file_op(a, fd, c, d)
                        },
                        SYS_FUNMAP_OLD => {
                            {
                                let contexts = crate::context::contexts();
                                let current = contexts.current().unwrap();
                                let current = current.read();
                                let name = current.name.lock();
                                println!("{:?} using deprecated funmap(...) call", name);
                            }
                            funmap_old(b)
                        },
                        _ => file_op(a, fd, c, d)
                    }
                }
            },
            SYS_CLASS_PATH => match a {
                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into),
                SYS_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16),
                SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
                SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
                _ => Err(Error::new(ENOSYS))
            },
            _ => match a {
                SYS_YIELD => sched_yield(),
                SYS_NANOSLEEP => nanosleep(
                    validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
                    }
                ),
                SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
                SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32),
                SYS_BRK => brk(b),
                SYS_GETPID => getpid().map(ContextId::into),
                SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                SYS_GETPPID => getppid().map(ContextId::into),
                SYS_CLONE => {
                    let b = CloneFlags::from_bits_truncate(b);
                    let old_rsp = stack.iret.rsp;
                    if b.contains(flag::CLONE_STACK) {
                        stack.iret.rsp = c;
                    }
                    let ret = clone(b, bp).map(ContextId::into);
                    stack.iret.rsp = old_rsp;
                    ret
                },
                SYS_EXIT => exit((b & 0xFF) << 8),
                SYS_KILL => kill(ContextId::from(b), c),
                SYS_WAITPID => waitpid(ContextId::from(b), c, WaitFlags::from_bits_truncate(d)).map(ContextId::into),
                SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
                SYS_IOPL => iopl(b, stack),
                SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
                SYS_GETEGID => getegid(),
                SYS_GETENS => getens(),
                SYS_GETEUID => geteuid(),
                SYS_GETGID => getgid(),
                SYS_GETNS => getns(),
                SYS_GETUID => getuid(),
                SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
                SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                SYS_SETREUID => setreuid(b as u32, c as u32),
                SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
                SYS_SETREGID => setregid(b as u32, c as u32),
                SYS_SIGACTION => sigaction(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
                    },
                    e
                ),
                SYS_SIGPROCMASK => sigprocmask(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const [u64; 2], 1).map(|s| &s[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut [u64; 2], 1).map(|s| &mut s[0])?)
                    }
                ),
                SYS_SIGRETURN => sigreturn(),
                SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                SYS_PHYSALLOC => physalloc(b),
                SYS_PHYSALLOC3 => physalloc3(b, c, &mut validate_slice_mut(d as *mut usize, 1)?[0]),
                SYS_PHYSFREE => physfree(b, c),
                SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)),
                SYS_PHYSUNMAP => physunmap(b),
                SYS_UMASK => umask(b),
                SYS_VIRTTOPHYS => virttophys(b),
                _ => Err(Error::new(ENOSYS))
            }
        }
    }

    /*
    let debug = {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            let name_raw = context.name.lock();
            let name = unsafe { core::str::from_utf8_unchecked(&name_raw) };
            if name == "file:/bin/cargo" || name == "file:/bin/rustc" {
                if a == SYS_CLOCK_GETTIME {
                    false
                } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
                    false
                } else {
                    true
                }
            } else {
                false
            }
        } else {
            false
        }
    };

    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        println!("{}", debug::format_call(a, b, c, d, e, f));
    }
    */

    // The next lines set the current syscall in the context struct, then once the inner() function
    // completes, we set the current syscall to none.
    //
    // When the code below falls out of scope it will release the lock
    // see the spin crate for details
    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = Some((a, b, c, d, e, f));
        }
    }

    let result = inner(a, b, c, d, e, f, bp, stack);

    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = None;
        }
    }

    /*
    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        print!("{} = ", debug::format_call(a, b, c, d, e, f));

        match result {
            Ok(ref ok) => {
                println!("Ok({} ({:#X}))", ok, ok);
            },
            Err(ref err) => {
                println!("Err({} ({:#X}))", err, err.errno);
            }
        }
    }
    */

    // errormux turns Result<usize> into -errno
    Error::mux(result)
}
<commit_msg>Fix printing of deprecation warning<commit_after>//!
//! This module provides syscall definitions and the necessary resources to parse incoming
//! syscalls

extern crate syscall;

pub use self::syscall::{data, error, flag, io, number, ptrace_event, scheme};

pub use self::driver::*;
pub use self::fs::*;
pub use self::futex::futex;
pub use self::privilege::*;
pub use self::process::*;
pub use self::time::*;
pub use self::validate::*;

use self::data::{SigAction, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags};
use self::number::*;

use crate::context::ContextId;
use crate::interrupt::InterruptStack;
use crate::scheme::{FileHandle, SchemeNamespace};

/// Debug
pub mod debug;

/// Driver syscalls
pub mod driver;

/// Filesystem syscalls
pub mod fs;

/// Fast userspace mutex
pub mod futex;

/// Privilege syscalls
pub mod privilege;

/// Process syscalls
pub mod process;

/// Time syscalls
pub mod time;

/// Validate input
pub mod validate;

/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> usize {
    #[inline(always)]
    fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> Result<usize> {
        //SYS_* is declared in kernel/syscall/src/number.rs
        match a & SYS_CLASS {
            SYS_CLASS_FILE => {
                let fd = FileHandle::from(b);
                match a & SYS_ARG {
                    SYS_ARG_SLICE => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
                    _ => match a {
                        SYS_CLOSE => close(fd),
                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
                        SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
                        SYS_FCNTL => fcntl(fd, c, d),
                        SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?),
                        SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?),
                        SYS_FUNMAP => funmap(b, c),
                        SYS_FMAP_OLD => {
                            {
                                let contexts = crate::context::contexts();
                                let current = contexts.current().unwrap();
                                let current = current.read();
                                let name = current.name.lock();
                                println!("{:?} using deprecated fmap(...) call", core::str::from_utf8(&name));
                            }
                            file_op(a, fd, c, d)
                        },
                        SYS_FUNMAP_OLD => {
                            {
                                let contexts = crate::context::contexts();
                                let current = contexts.current().unwrap();
                                let current = current.read();
                                let name = current.name.lock();
                                println!("{:?} using deprecated funmap(...) call", core::str::from_utf8(&name));
                            }
                            funmap_old(b)
                        },
                        _ => file_op(a, fd, c, d)
                    }
                }
            },
            SYS_CLASS_PATH => match a {
                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into),
                SYS_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16),
                SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
                SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
                _ => Err(Error::new(ENOSYS))
            },
            _ => match a {
                SYS_YIELD => sched_yield(),
                SYS_NANOSLEEP => nanosleep(
                    validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
                    }
                ),
                SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
                SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32),
                SYS_BRK => brk(b),
                SYS_GETPID => getpid().map(ContextId::into),
                SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                SYS_GETPPID => getppid().map(ContextId::into),
                SYS_CLONE => {
                    let b = CloneFlags::from_bits_truncate(b);
                    let old_rsp = stack.iret.rsp;
                    if b.contains(flag::CLONE_STACK) {
                        stack.iret.rsp = c;
                    }
                    let ret = clone(b, bp).map(ContextId::into);
                    stack.iret.rsp = old_rsp;
                    ret
                },
                SYS_EXIT => exit((b & 0xFF) << 8),
                SYS_KILL => kill(ContextId::from(b), c),
                SYS_WAITPID => waitpid(ContextId::from(b), c, WaitFlags::from_bits_truncate(d)).map(ContextId::into),
                SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
                SYS_IOPL => iopl(b, stack),
                SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
                SYS_GETEGID => getegid(),
                SYS_GETENS => getens(),
                SYS_GETEUID => geteuid(),
                SYS_GETGID => getgid(),
                SYS_GETNS => getns(),
                SYS_GETUID => getuid(),
                SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
                SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                SYS_SETREUID => setreuid(b as u32, c as u32),
                SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
                SYS_SETREGID => setregid(b as u32, c as u32),
                SYS_SIGACTION => sigaction(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
                    },
                    e
                ),
                SYS_SIGPROCMASK => sigprocmask(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const [u64; 2], 1).map(|s| &s[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut [u64; 2], 1).map(|s| &mut s[0])?)
                    }
                ),
                SYS_SIGRETURN => sigreturn(),
                SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                SYS_PHYSALLOC => physalloc(b),
                SYS_PHYSALLOC3 => physalloc3(b, c, &mut validate_slice_mut(d as *mut usize, 1)?[0]),
                SYS_PHYSFREE => physfree(b, c),
                SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)),
                SYS_PHYSUNMAP => physunmap(b),
                SYS_UMASK => umask(b),
                SYS_VIRTTOPHYS => virttophys(b),
                _ => Err(Error::new(ENOSYS))
            }
        }
    }

    /*
    let debug = {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            let name_raw = context.name.lock();
            let name = unsafe { core::str::from_utf8_unchecked(&name_raw) };
            if name == "file:/bin/cargo" || name == "file:/bin/rustc" {
                if a == SYS_CLOCK_GETTIME {
                    false
                } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
                    false
                } else {
                    true
                }
            } else {
                false
            }
        } else {
            false
        }
    };

    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        println!("{}", debug::format_call(a, b, c, d, e, f));
    }
    */

    // The next lines set the current syscall in the context struct, then once the inner() function
    // completes, we set the current syscall to none.
    //
    // When the code below falls out of scope it will release the lock
    // see the spin crate for details
    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = Some((a, b, c, d, e, f));
        }
    }

    let result = inner(a, b, c, d, e, f, bp, stack);

    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = None;
        }
    }

    /*
    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        print!("{} = ", debug::format_call(a, b, c, d, e, f));

        match result {
            Ok(ref ok) => {
                println!("Ok({} ({:#X}))", ok, ok);
            },
            Err(ref err) => {
                println!("Err({} ({:#X}))", err, err.errno);
            }
        }
    }
    */

    // errormux turns Result<usize> into -errno
    Error::mux(result)
}
<|endoftext|>


<commit_before>use std::error::Error as StdError;
use base::ast::Typed;
use base::types::{TypeEnv, display_type};
use vm::vm::{VM, RootStr};
use vm::api::{IO, Function, WithVM};

use embed_lang::{typecheck_expr, load_file};

fn type_of_expr(args: WithVM<RootStr>) -> IO<String> {
    let WithVM { vm, value: args } = args;
    IO::Value(match typecheck_expr(vm, "<repl>", &args, false) {
        Ok((expr, _)) => {
            let ref env = vm.env();
            let symbols = vm.get_symbols();
            format!("{}", display_type(&*symbols, &expr.env_type_of(env)))
        }
        Err(msg) => format!("{}", msg),
    })
}

fn find_type_info(args: WithVM<RootStr>) -> IO<String> {
    let vm = args.vm;
    let args = args.value.trim();
    IO::Value(match vm.env().find_type_info(&vm.symbol(args)) {
        Some((generic_args, typ)) => {
            let fmt = || -> Result<String, ::std::fmt::Error> {
                use std::fmt::Write;
                let mut buffer = String::new();
                try!(write!(&mut buffer, "type {}", args));
                for g in generic_args {
                    try!(write!(&mut buffer, " {}", vm.symbol_string(g.id)))
                }
                try!(write!(&mut buffer, " = "));
                match typ {
                    Some(typ) => {
                        let symbols = vm.get_symbols();
                        try!(write!(&mut buffer, "{}", display_type(&*symbols, typ)))
                    }
                    None => try!(write!(&mut buffer, "<abstract>")),
                }
                Ok(buffer)
            };
            fmt().unwrap()
        }
        None => format!("'{}' is not a type", args),
    })
}

fn f1<A, R>(f: fn(A) -> R) -> fn(A) -> R {
    f
}

fn compile_repl(vm: &VM) -> Result<(), Box<StdError>> {
    try!(vm.define_global("repl_prim",
                          record!(
        type_of_expr => f1(type_of_expr),
        find_type_info => f1(find_type_info)
    )));
    try!(load_file(vm, "std/prelude.hs"));
    try!(load_file(vm, "std/repl.hs"));
    Ok(())
}

#[allow(dead_code)]
pub fn run() -> Result<(), Box<StdError>> {
    let vm = VM::new();
    try!(compile_repl(&vm));
    let mut repl: Function<fn (()) -> IO<()>> = try!(vm.get_global("std.repl"));
    try!(repl.call(()));
    Ok(())
}

#[cfg(test)]
mod tests {
    use embed_lang::new_vm;
    use super::compile_repl;

    #[test]
    fn compile_repl_test() {
        let vm = new_vm();
        compile_repl(&vm).unwrap_or_else(|err| panic!("{}", err));
    }
}
<commit_msg>fix(repl): Use the new_vm function when creating the REPL so primitives are laoded<commit_after>use std::error::Error as StdError;
use base::ast::Typed;
use base::types::{TypeEnv, display_type};
use vm::vm::{VM, RootStr};
use vm::api::{IO, Function, WithVM};

use embed_lang::{typecheck_expr, load_file, new_vm};

fn type_of_expr(args: WithVM<RootStr>) -> IO<String> {
    let WithVM { vm, value: args } = args;
    IO::Value(match typecheck_expr(vm, "<repl>", &args, false) {
        Ok((expr, _)) => {
            let ref env = vm.env();
            let symbols = vm.get_symbols();
            format!("{}", display_type(&*symbols, &expr.env_type_of(env)))
        }
        Err(msg) => format!("{}", msg),
    })
}

fn find_type_info(args: WithVM<RootStr>) -> IO<String> {
    let vm = args.vm;
    let args = args.value.trim();
    IO::Value(match vm.env().find_type_info(&vm.symbol(args)) {
        Some((generic_args, typ)) => {
            let fmt = || -> Result<String, ::std::fmt::Error> {
                use std::fmt::Write;
                let mut buffer = String::new();
                try!(write!(&mut buffer, "type {}", args));
                for g in generic_args {
                    try!(write!(&mut buffer, " {}", vm.symbol_string(g.id)))
                }
                try!(write!(&mut buffer, " = "));
                match typ {
                    Some(typ) => {
                        let symbols = vm.get_symbols();
                        try!(write!(&mut buffer, "{}", display_type(&*symbols, typ)))
                    }
                    None => try!(write!(&mut buffer, "<abstract>")),
                }
                Ok(buffer)
            };
            fmt().unwrap()
        }
        None => format!("'{}' is not a type", args),
    })
}

fn f1<A, R>(f: fn(A) -> R) -> fn(A) -> R {
    f
}

fn compile_repl(vm: &VM) -> Result<(), Box<StdError>> {
    try!(vm.define_global("repl_prim",
                          record!(
        type_of_expr => f1(type_of_expr),
        find_type_info => f1(find_type_info)
    )));
    try!(load_file(vm, "std/prelude.hs"));
    try!(load_file(vm, "std/repl.hs"));
    Ok(())
}

#[allow(dead_code)]
pub fn run() -> Result<(), Box<StdError>> {
    let vm = new_vm();
    try!(compile_repl(&vm));
    let mut repl: Function<fn (()) -> IO<()>> = try!(vm.get_global("std.repl"));
    try!(repl.call(()));
    Ok(())
}

#[cfg(test)]
mod tests {
    use embed_lang::new_vm;
    use super::compile_repl;

    #[test]
    fn compile_repl_test() {
        let vm = new_vm();
        compile_repl(&vm).unwrap_or_else(|err| panic!("{}", err));
    }
}
<|endoftext|>


<commit_before>extern crate utp;

use std::thread;
use utp::UtpStream;
use std::io::{Read, Write};

macro_rules! iotry {
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => panic!("{}", e) })
}

fn next_test_port() -> u16 {
    use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
    static NEXT_OFFSET: AtomicUsize = ATOMIC_USIZE_INIT;
    const BASE_PORT: u16 = 9600;
    BASE_PORT + NEXT_OFFSET.fetch_add(1, Ordering::Relaxed) as u16
}

fn next_test_ip4<'a>() -> (&'a str, u16) {
    ("127.0.0.1", next_test_port())
}

#[test]
fn test_stream_open_and_close() {
    let server_addr = next_test_ip4();
    let mut server = iotry!(UtpStream::bind(server_addr));

    thread::spawn(move || {
        let mut client = iotry!(UtpStream::connect(server_addr));
        iotry!(client.close());
        drop(client);
    });

    let mut received = vec!();
    iotry!(server.read_to_end(&mut received));
    iotry!(server.close());
}

#[test]
fn test_stream_small_data() {
    // Fits in a packet
    const LEN: usize = 1024;
    let data: Vec<u8> = (0..LEN).map(|idx| idx as u8).collect();
    assert_eq!(LEN, data.len());

    let d = data.clone();
    let server_addr = next_test_ip4();
    let mut server = iotry!(UtpStream::bind(server_addr));

    thread::spawn(move || {
        let mut client = iotry!(UtpStream::connect(server_addr));
        iotry!(client.write(&d[..]));
        iotry!(client.close());
    });

    let mut received = Vec::with_capacity(LEN);
    iotry!(server.read_to_end(&mut received));
    assert!(!received.is_empty());
    assert_eq!(received.len(), data.len());
    assert_eq!(received, data);
}

#[test]
fn test_stream_large_data() {
    // Has to be sent over several packets
    const LEN: usize = 1024 * 1024;
    let data: Vec<u8> = (0..LEN).map(|idx| idx as u8).collect();
    assert_eq!(LEN, data.len());

    let d = data.clone();
    let server_addr = next_test_ip4();
    let mut server = iotry!(UtpStream::bind(server_addr));

    thread::spawn(move || {
        let mut client = iotry!(UtpStream::connect(server_addr));
        iotry!(client.write(&d[..]));
        iotry!(client.close());
    });

    let mut received = Vec::with_capacity(LEN);
    iotry!(server.read_to_end(&mut received));
    assert!(!received.is_empty());
    assert_eq!(received.len(), data.len());
    assert_eq!(received, data);
}

#[test]
fn test_stream_successive_reads() {
    const LEN: usize = 1024;
    let data: Vec<u8> = (0..LEN).map(|idx| idx as u8).collect();
    assert_eq!(LEN, data.len());

    let d = data.clone();
    let server_addr = next_test_ip4();
    let mut server = iotry!(UtpStream::bind(server_addr));

    thread::spawn(move || {
        let mut client = iotry!(UtpStream::connect(server_addr));
        iotry!(client.write(&d[..]));
        iotry!(client.close());
    });

    let mut received = Vec::with_capacity(LEN);
    iotry!(server.read_to_end(&mut received));
    assert!(!received.is_empty());
    assert_eq!(received.len(), data.len());
    assert_eq!(received, data);

    match server.read(&mut received) {
        Ok(0) => (),
        e => panic!("should have returned Ok(0), got {:?}", e),
    };
}
<commit_msg>Replace unnecessary `match` with `unwrap`.<commit_after>extern crate utp;

use std::thread;
use utp::UtpStream;
use std::io::{Read, Write};

macro_rules! iotry {
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => panic!("{}", e) })
}

fn next_test_port() -> u16 {
    use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
    static NEXT_OFFSET: AtomicUsize = ATOMIC_USIZE_INIT;
    const BASE_PORT: u16 = 9600;
    BASE_PORT + NEXT_OFFSET.fetch_add(1, Ordering::Relaxed) as u16
}

fn next_test_ip4<'a>() -> (&'a str, u16) {
    ("127.0.0.1", next_test_port())
}

#[test]
fn test_stream_open_and_close() {
    let server_addr = next_test_ip4();
    let mut server = iotry!(UtpStream::bind(server_addr));

    thread::spawn(move || {
        let mut client = iotry!(UtpStream::connect(server_addr));
        iotry!(client.close());
        drop(client);
    });

    let mut received = vec!();
    iotry!(server.read_to_end(&mut received));
    iotry!(server.close());
}

#[test]
fn test_stream_small_data() {
    // Fits in a packet
    const LEN: usize = 1024;
    let data: Vec<u8> = (0..LEN).map(|idx| idx as u8).collect();
    assert_eq!(LEN, data.len());

    let d = data.clone();
    let server_addr = next_test_ip4();
    let mut server = iotry!(UtpStream::bind(server_addr));

    thread::spawn(move || {
        let mut client = iotry!(UtpStream::connect(server_addr));
        iotry!(client.write(&d[..]));
        iotry!(client.close());
    });

    let mut received = Vec::with_capacity(LEN);
    iotry!(server.read_to_end(&mut received));
    assert!(!received.is_empty());
    assert_eq!(received.len(), data.len());
    assert_eq!(received, data);
}

#[test]
fn test_stream_large_data() {
    // Has to be sent over several packets
    const LEN: usize = 1024 * 1024;
    let data: Vec<u8> = (0..LEN).map(|idx| idx as u8).collect();
    assert_eq!(LEN, data.len());

    let d = data.clone();
    let server_addr = next_test_ip4();
    let mut server = iotry!(UtpStream::bind(server_addr));

    thread::spawn(move || {
        let mut client = iotry!(UtpStream::connect(server_addr));
        iotry!(client.write(&d[..]));
        iotry!(client.close());
    });

    let mut received = Vec::with_capacity(LEN);
    iotry!(server.read_to_end(&mut received));
    assert!(!received.is_empty());
    assert_eq!(received.len(), data.len());
    assert_eq!(received, data);
}

#[test]
fn test_stream_successive_reads() {
    const LEN: usize = 1024;
    let data: Vec<u8> = (0..LEN).map(|idx| idx as u8).collect();
    assert_eq!(LEN, data.len());

    let d = data.clone();
    let server_addr = next_test_ip4();
    let mut server = iotry!(UtpStream::bind(server_addr));

    thread::spawn(move || {
        let mut client = iotry!(UtpStream::connect(server_addr));
        iotry!(client.write(&d[..]));
        iotry!(client.close());
    });

    let mut received = Vec::with_capacity(LEN);
    iotry!(server.read_to_end(&mut received));
    assert!(!received.is_empty());
    assert_eq!(received.len(), data.len());
    assert_eq!(received, data);

    assert_eq!(server.read(&mut received).unwrap(), 0);
}
<|endoftext|>


<commit_before>use ::nfa::{State, Edge, NFA};

#[cfg(test)] mod spec;

#[derive(Clone,PartialEq,Debug)]
struct PotentialMatch {
    current_state: Option<State>,
    remaining_text: String
}

impl PotentialMatch {
    pub fn advance(&self, nfa: &NFA) -> Vec<PotentialMatch> {
        if self.current_state.is_none() {
            return vec![self.clone()];
        }

        let current_state = self.current_state.clone().unwrap();

        match current_state {
            State::State{ref edge, ref out} => {
                vec![self.next_for_edge(nfa, edge, out)]
            },
            State::Split{ref s1, ref out1, ref s2, ref out2} => {
                let mut s1_next = self.next_for_edge(nfa, s1, out1);
                let mut s2_next = self.next_for_edge(nfa, s2, out2);
                vec![s1_next, s2_next]
            }
        }
    }

    fn next(&self, nfa: &NFA, edge: &Option<char>, out: &Edge) -> Option<PotentialMatch> {
        match edge {
            &Some(val) => {
                if self.remaining_text.is_empty() {
                    // no character to consume, this potential match cannot continue
                    return None;
                }

                if val == self.remaining_text.as_bytes()[0] as char {
                    // can consume char and advance along edge
                    match out {
                        &Edge::End => {
                            Some(PotentialMatch::new(None,
                                                     &self.remaining_text[1..]))
                        },
                        &Edge::Id(id) => {
                            Some(PotentialMatch::new(nfa.get_state(id),
                            &self.remaining_text[1..]))
                        },
                        _ => panic!()
                    }
                } else {
                    // potential match cannot proceed, mismatched character
                    None
                }
            },
            &None => {
                // can advance along empty edge
                match out {
                    &Edge::End => {
                        Some(PotentialMatch::new(None,
                                                 &self.remaining_text))
                    },
                    &Edge::Id(id) => {
                        Some(PotentialMatch::new(
                            nfa.get_state(id),
                            &self.remaining_text))
                    },
                    _ => panic!("cannot evaluate incomplete NFA")
                }
            }
        }

    }

    pub fn is_match(&self) -> bool {
        self.current_state.is_none()
    }

    pub fn new(state: Option<State>, remaining_text: &str) -> PotentialMatch {
        PotentialMatch {
            current_state: state,
            remaining_text: remaining_text.to_owned()
        }
    }
}

pub struct Matcher {
    nfa: NFA,
    text: String
}

impl Matcher {
    pub fn new(nfa: NFA, text: &str) -> Matcher {
        Matcher {
            nfa: nfa,
            text: text.to_owned()
        }
    }

    pub fn run(&mut self) -> bool {

        if self.nfa.num_states() == 0 { // regex is empty
            return true;
        }

        let mut states = vec![
            PotentialMatch::new(Some(self.nfa.get_start().unwrap()),
                                &self.text)
        ];

        while Self::has_valid_state(&states) {

            let mut updated_states = Vec::new();

            for state in states {
                let new_states = state.advance(&self.nfa);

                for s in new_states {
                    if s.is_match() {
                        return true;
                    } else {
                        updated_states.push(s);
                    }
                }
            }

            states = updated_states;
        }

        false
    }

    fn has_valid_state(states: &Vec<PotentialMatch>) -> bool {
        states.len() > 0
    }
}

<commit_msg>refactor next_for_edge<commit_after>use ::nfa::{State, Edge, NFA};

#[cfg(test)] mod spec;

#[derive(Clone,PartialEq,Debug)]
struct PotentialMatch {
    current_state: Option<State>,
    remaining_text: String
}

impl PotentialMatch {
    pub fn advance(&self, nfa: &NFA) -> Vec<PotentialMatch> {
        if self.current_state.is_none() {
            return vec![self.clone()];
        }

        let current_state = self.current_state.clone().unwrap();

        match current_state {
            State::State{ref edge, ref out} => {

                let mut result = Vec::new();
                Self::push_option(
                    &mut result,
                    self.next_for_edge(nfa, edge, out));
                result
            },
            State::Split{ref s1, ref out1, ref s2, ref out2} => {
                let mut s1_next = self.next_for_edge(nfa, s1, out1);
                let mut s2_next = self.next_for_edge(nfa, s2, out2);

                let mut result = Vec::new();
                Self::push_option(&mut result, s1_next);
                Self::push_option(&mut result, s2_next);

                result
            }
        }
    }

    fn next_for_edge(&self, nfa: &NFA, edge: &Option<char>, out: &Edge) -> Option<PotentialMatch> {
        match edge {
            &Some(val) => {
                if self.remaining_text.is_empty() {
                    // no character to consume, this potential match cannot continue
                    return None;
                }

                if val == self.remaining_text.as_bytes()[0] as char {
                    // can consume char and advance along edge
                    match out {
                        &Edge::End => {
                            Some(PotentialMatch::new(None,
                                                     &self.remaining_text[1..]))
                        },
                        &Edge::Id(id) => {
                            Some(PotentialMatch::new(nfa.get_state(id),
                            &self.remaining_text[1..]))
                        },
                        _ => panic!()
                    }
                } else {
                    // potential match cannot proceed, mismatched character
                    None
                }
            },
            &None => {
                // can advance along empty edge
                match out {
                    &Edge::End => {
                        Some(PotentialMatch::new(None,
                                                 &self.remaining_text))
                    },
                    &Edge::Id(id) => {
                        Some(PotentialMatch::new(
                            nfa.get_state(id),
                            &self.remaining_text))
                    },
                    _ => panic!("cannot evaluate incomplete NFA")
                }
            }
        }

    }

    pub fn push_option<T>(vec: &mut Vec<T>, item: Option<T>) {
        match item {
            Some(item) => vec.push(item),
            None => ()
        }
    }

    pub fn is_match(&self) -> bool {
        self.current_state.is_none()
    }

    pub fn new(state: Option<State>, remaining_text: &str) -> PotentialMatch {
        PotentialMatch {
            current_state: state,
            remaining_text: remaining_text.to_owned()
        }
    }
}

pub struct Matcher {
    nfa: NFA,
    text: String
}

impl Matcher {
    pub fn new(nfa: NFA, text: &str) -> Matcher {
        Matcher {
            nfa: nfa,
            text: text.to_owned()
        }
    }

    pub fn run(&mut self) -> bool {

        if self.nfa.num_states() == 0 { // regex is empty
            return true;
        }

        let mut states = vec![
            PotentialMatch::new(Some(self.nfa.get_start().unwrap()),
                                &self.text)
        ];

        while Self::has_valid_state(&states) {

            let mut updated_states = Vec::new();

            for state in states {
                let new_states = state.advance(&self.nfa);

                for s in new_states {
                    if s.is_match() {
                        return true;
                    } else {
                        updated_states.push(s);
                    }
                }
            }

            states = updated_states;
        }

        false
    }

    fn has_valid_state(states: &Vec<PotentialMatch>) -> bool {
        states.len() > 0
    }
}

<|endoftext|>


<commit_before>//! Processes Twee files and builds an abstract syntax tree.
//!
//! The Frontend is responsible for processing a Twee file by
//! generating a Token Stream from the input and parsing this stream to build
//! an Abstract Syntax Tree.
//!
//! # Example
//!
//! This small example shows how the different submodules interact and can
//! be used to parse a Twee-File.
//!
//! ```
//! # extern crate zwreec;
//! use std::io::Cursor;
//!
//! let cfg = zwreec::config::Config::default_config();
//! let mut twee = Cursor::new("::Start\nHello World".to_string().into_bytes());
//!
//! // Generate Token Stream
//! let tokens = zwreec::frontend::lexer::lex(&cfg, &mut twee);
//!
//! // Parse Tokens
//! let p = zwreec::frontend::parser::Parser::new(&cfg);
//! let ast_builder = zwreec::frontend::ast::ASTBuilder::new(&cfg);
//! let ast = ast_builder.build(
//!     p.parse(tokens)
//! );
//! ```

pub mod ast;
pub mod codegen;
pub mod evaluate_expression;
pub mod expressionparser;
pub mod lexer;
pub mod parser;
pub mod screener;
<commit_msg>Fixed doctest<commit_after>//! Processes Twee files and builds an abstract syntax tree.
//!
//! The Frontend is responsible for processing a Twee file by
//! generating a Token Stream from the input and parsing this stream to build
//! an Abstract Syntax Tree.
//!
//! # Example
//!
//! This small example shows how the different submodules interact and can
//! be used to parse a Twee-File.
//!
//! ```
//! # extern crate zwreec;
//! use std::io::Cursor;
//!
//! let cfg = zwreec::config::Config::default_config();
//! let mut twee = Cursor::new("::Start\nHello World".to_string().into_bytes());
//!
//! // Generate Token Stream
//! let tokens = zwreec::frontend::lexer::lex(&cfg, &mut twee);
//!
//! // Parse Tokens
//! let p = zwreec::frontend::parser::Parser::new(&cfg);
//! let ast: Vec<zwreec::frontend::ast::ASTNode> = zwreec::frontend::ast::ASTBuilder::build(&cfg, p.parse(tokens)).collect();
//! ```

pub mod ast;
pub mod codegen;
pub mod evaluate_expression;
pub mod expressionparser;
pub mod lexer;
pub mod parser;
pub mod screener;
<|endoftext|>


<commit_before>use color::Color3;
use id_allocator::IdAllocator;
use nalgebra::{Pnt3, Vec3, normalize};
use ncollide::bounding_volume::AABB;
use state::EntityId;
use std::cmp::{partial_min, partial_max};
use std::collections::RingBuf;
use std::num::Float;
use std::rand::{Rng, SeedableRng, IsaacRng};
use terrain::LOD_QUALITY;
use terrain_block::{TerrainBlock, BLOCK_WIDTH};

#[inline(always)]
fn fmod(mut dividend: f64, divisor: f64) -> f64 {
  dividend -= divisor * (dividend / divisor).floor();
  if dividend < 0.0 || dividend >= divisor{
    // clamp
    dividend = 0.0;
  }
  dividend
}

fn sqr_distance(p1: &Pnt3<f32>, p2: &Pnt3<f32>) -> f32 {
  let d = *p1 - *p2.as_vec();
  d.x*d.x + d.y*d.y + d.z*d.z
}

/// Use one-octave perlin noise local maxima to place trees.
pub struct TreePlacer {
  seed: u32,
}

impl TreePlacer {
  pub fn new(seed: u32) -> TreePlacer {
    TreePlacer {
      seed: seed,
    }
  }

  fn rng_at(&self, center: &Pnt3<f32>, mut seed: Vec<u32>) -> IsaacRng {
    let center = *center * (LOD_QUALITY[0] as f32) / (BLOCK_WIDTH as f32);
    seed.push_all(&[self.seed, center.x as u32, center.z as u32]);
    SeedableRng::from_seed(seed.as_slice())
  }

  pub fn should_place_tree(&self, center: &Pnt3<f32>) -> bool {
    let mut rng = self.rng_at(center, vec!(0));
    rng.next_u32() > 0xFFF7FFFF
  }

  pub fn place_tree(
    &self,
    mut center: Pnt3<f32>,
    id_allocator: &mut IdAllocator<EntityId>,
    block: &mut TerrainBlock,
  ) {
    let normals = [
      normalize(&Vec3::new(-1.0, -1.0, -1.0)),
      normalize(&Vec3::new(-1.0, -1.0,  1.0)),
      normalize(&Vec3::new( 1.0, -1.0,  1.0)),
      normalize(&Vec3::new( 1.0, -1.0, -1.0)),
      normalize(&Vec3::new(-1.0,  1.0, -1.0)),
      normalize(&Vec3::new(-1.0,  1.0,  1.0)),
      normalize(&Vec3::new( 1.0,  1.0,  1.0)),
      normalize(&Vec3::new( 1.0,  1.0, -1.0)),
    ];

    let mut place_side =
      |&mut:
        corners: &[Pnt3<f32>],
        color: &Color3<f32>,
        idx1,
        idx2,
        idx3,
        idx4,
      | {
        let n1 = normals.get(idx1).unwrap();
        let n2 = normals.get(idx2).unwrap();
        let n3 = normals.get(idx3).unwrap();
        let n4 = normals.get(idx4).unwrap();

        let v1 = corners.get(idx1).unwrap();
        let v2 = corners.get(idx2).unwrap();
        let v3 = corners.get(idx3).unwrap();
        let v4 = corners.get(idx4).unwrap();

        block.vertex_coordinates.push_all(&[
          v1.x, v1.y, v1.z,
          v2.x, v2.y, v2.z,
          v4.x, v4.y, v4.z,

          v1.x, v1.y, v1.z,
          v4.x, v4.y, v4.z,
          v3.x, v3.y, v3.z,
        ]);

        block.normals.push_all(&[
          n1.x, n1.y, n1.z,
          n2.x, n2.y, n2.z,
          n4.x, n4.y, n4.z,

          n1.x, n1.y, n1.z,
          n4.x, n4.y, n4.z,
          n3.x, n3.y, n3.z,
        ]);

        block.colors.push_all(&[
          color.r, color.g, color.b,
          color.r, color.g, color.b,
        ]);

        let minx = partial_min(v1.x, v2.x).unwrap();
        let maxx = partial_max(v1.x, v2.x).unwrap();
        let minz = partial_min(v1.z, v2.z).unwrap();
        let maxz = partial_max(v1.z, v2.z).unwrap();

        let bounds =
          AABB::new(
            Pnt3::new(minx, v1.y, minz),
            Pnt3::new(maxx, v3.y, maxz),
          );

        let id1 = id_allocator.allocate();
        let id2 = id_allocator.allocate();
        block.ids.push_all(&[id1, id2]);

        block.bounds.insert(id1, bounds.clone());
        block.bounds.insert(id2, bounds);
      };

    let mut place_block =
      |&mut: low_center: &Pnt3<f32>, high_center: &Pnt3<f32>, radius: f32, color| {
        let corners = [
          *low_center + Vec3::new(-radius, 0.0, -radius),
          *low_center + Vec3::new(-radius, 0.0,  radius),
          *low_center + Vec3::new( radius, 0.0,  radius),
          *low_center + Vec3::new( radius, 0.0, -radius),
          *high_center + Vec3::new(-radius, 0.0, -radius),
          *high_center + Vec3::new(-radius, 0.0,  radius),
          *high_center + Vec3::new( radius, 0.0,  radius),
          *high_center + Vec3::new( radius, 0.0, -radius),
        ];

        place_side(&corners, &color, 0, 1, 4, 5);
        place_side(&corners, &color, 1, 2, 5, 6);
        place_side(&corners, &color, 2, 3, 6, 7);
        place_side(&corners, &color, 3, 0, 7, 4);
      };

    let wood_color = Color3::of_rgb(0.4, 0.3, 0.1);

    let mut rng = self.rng_at(&center, vec!(1));
    let mass = (rng.next_u32() as f32) / (0x10000 as f32) / (0x10000 as f32);
    let mass = 0.1 + mass * 0.9;
    let mass = partial_min(partial_max(0.0, mass).unwrap(), 1.0).unwrap();

    {
      let radius = mass * mass * 2.0;
      let height = mass * 16.0;
      place_block(&center, &(center + Vec3::new(0.0, height, 0.0)), radius, wood_color);
      center = center + Vec3::new(0.0, height, 0.0);
    }

    {
      let radius = mass * mass * 16.0;
      let height = mass * mass * 16.0;

      let mut points: Vec<Pnt3<_>> =
        range(0, (radius * radius * height / 8.0) as u32)
        .map(|_| {
          let x = rng.next_u32();
          let y = rng.next_u32();
          let z = rng.next_u32();
          Pnt3::new(
            fmod(x as f64, 2.0 * radius as f64) as f32 - radius,
            fmod(y as f64, height as f64) as f32,
            fmod(z as f64, 2.0 * radius as f64) as f32 - radius,
          )
        })
        .map(|p| p + *center.as_vec())
        .collect();

      let mut fringe = RingBuf::new();
      fringe.push_back(center);

      while let Some(p) = fringe.pop_front() {
        let mut i = 0;
        while i < points.len() {
          let &target = points.get(i).unwrap();
          if sqr_distance(&p, &target) <= 4.0*4.0 {
            if p.y < target.y {
              place_block(&p, &target, 0.2, wood_color);
            } else {
              place_block(&target, &p, 0.2, wood_color);
            }
            fringe.push_back(target);
            points.swap_remove(i);
          } else {
            i += 1;
          }
        }
      }
    }
  }
}
<commit_msg>TreePlacer's place_block creates top and bottom faces<commit_after>use color::Color3;
use id_allocator::IdAllocator;
use nalgebra::{Pnt3, Vec3, normalize};
use ncollide::bounding_volume::AABB;
use state::EntityId;
use std::cmp::{partial_min, partial_max};
use std::collections::RingBuf;
use std::num::Float;
use std::rand::{Rng, SeedableRng, IsaacRng};
use terrain::LOD_QUALITY;
use terrain_block::{TerrainBlock, BLOCK_WIDTH};

#[inline(always)]
fn fmod(mut dividend: f64, divisor: f64) -> f64 {
  dividend -= divisor * (dividend / divisor).floor();
  if dividend < 0.0 || dividend >= divisor{
    // clamp
    dividend = 0.0;
  }
  dividend
}

fn sqr_distance(p1: &Pnt3<f32>, p2: &Pnt3<f32>) -> f32 {
  let d = *p1 - *p2.as_vec();
  d.x*d.x + d.y*d.y + d.z*d.z
}

/// Use one-octave perlin noise local maxima to place trees.
pub struct TreePlacer {
  seed: u32,
}

impl TreePlacer {
  pub fn new(seed: u32) -> TreePlacer {
    TreePlacer {
      seed: seed,
    }
  }

  fn rng_at(&self, center: &Pnt3<f32>, mut seed: Vec<u32>) -> IsaacRng {
    let center = *center * (LOD_QUALITY[0] as f32) / (BLOCK_WIDTH as f32);
    seed.push_all(&[self.seed, center.x as u32, center.z as u32]);
    SeedableRng::from_seed(seed.as_slice())
  }

  pub fn should_place_tree(&self, center: &Pnt3<f32>) -> bool {
    let mut rng = self.rng_at(center, vec!(0));
    rng.next_u32() > 0xFFF7FFFF
  }

  pub fn place_tree(
    &self,
    mut center: Pnt3<f32>,
    id_allocator: &mut IdAllocator<EntityId>,
    block: &mut TerrainBlock,
  ) {
    let normals = [
      normalize(&Vec3::new(-1.0, -1.0, -1.0)),
      normalize(&Vec3::new(-1.0, -1.0,  1.0)),
      normalize(&Vec3::new( 1.0, -1.0,  1.0)),
      normalize(&Vec3::new( 1.0, -1.0, -1.0)),
      normalize(&Vec3::new(-1.0,  1.0, -1.0)),
      normalize(&Vec3::new(-1.0,  1.0,  1.0)),
      normalize(&Vec3::new( 1.0,  1.0,  1.0)),
      normalize(&Vec3::new( 1.0,  1.0, -1.0)),
    ];

    let mut place_side =
      |&mut:
        corners: &[Pnt3<f32>],
        color: &Color3<f32>,
        idx1,
        idx2,
        idx3,
        idx4,
      | {
        let n1 = normals.get(idx1).unwrap();
        let n2 = normals.get(idx2).unwrap();
        let n3 = normals.get(idx3).unwrap();
        let n4 = normals.get(idx4).unwrap();

        let v1 = corners.get(idx1).unwrap();
        let v2 = corners.get(idx2).unwrap();
        let v3 = corners.get(idx3).unwrap();
        let v4 = corners.get(idx4).unwrap();

        block.vertex_coordinates.push_all(&[
          v1.x, v1.y, v1.z,
          v2.x, v2.y, v2.z,
          v4.x, v4.y, v4.z,

          v1.x, v1.y, v1.z,
          v4.x, v4.y, v4.z,
          v3.x, v3.y, v3.z,
        ]);

        block.normals.push_all(&[
          n1.x, n1.y, n1.z,
          n2.x, n2.y, n2.z,
          n4.x, n4.y, n4.z,

          n1.x, n1.y, n1.z,
          n4.x, n4.y, n4.z,
          n3.x, n3.y, n3.z,
        ]);

        block.colors.push_all(&[
          color.r, color.g, color.b,
          color.r, color.g, color.b,
        ]);

        let minx = partial_min(v1.x, v2.x).unwrap();
        let maxx = partial_max(v1.x, v2.x).unwrap();
        let minz = partial_min(v1.z, v2.z).unwrap();
        let maxz = partial_max(v1.z, v2.z).unwrap();

        let bounds =
          AABB::new(
            Pnt3::new(minx, v1.y, minz),
            Pnt3::new(maxx, v3.y, maxz),
          );

        let id1 = id_allocator.allocate();
        let id2 = id_allocator.allocate();
        block.ids.push_all(&[id1, id2]);

        block.bounds.insert(id1, bounds.clone());
        block.bounds.insert(id2, bounds);
      };

    let mut place_block =
      |&mut: low_center: &Pnt3<f32>, high_center: &Pnt3<f32>, radius: f32, color| {
        let corners = [
          *low_center + Vec3::new(-radius, 0.0, -radius),
          *low_center + Vec3::new(-radius, 0.0,  radius),
          *low_center + Vec3::new( radius, 0.0,  radius),
          *low_center + Vec3::new( radius, 0.0, -radius),
          *high_center + Vec3::new(-radius, 0.0, -radius),
          *high_center + Vec3::new(-radius, 0.0,  radius),
          *high_center + Vec3::new( radius, 0.0,  radius),
          *high_center + Vec3::new( radius, 0.0, -radius),
        ];

        place_side(&corners, &color, 0, 1, 4, 5);
        place_side(&corners, &color, 1, 2, 5, 6);
        place_side(&corners, &color, 2, 3, 6, 7);
        place_side(&corners, &color, 3, 0, 7, 4);
        place_side(&corners, &color, 1, 0, 2, 3);
        place_side(&corners, &color, 4, 5, 7, 6);
      };

    let wood_color = Color3::of_rgb(0.4, 0.3, 0.1);

    let mut rng = self.rng_at(&center, vec!(1));
    let mass = (rng.next_u32() as f32) / (0x10000 as f32) / (0x10000 as f32);
    let mass = 0.1 + mass * 0.9;
    let mass = partial_min(partial_max(0.0, mass).unwrap(), 1.0).unwrap();

    {
      let radius = mass * mass * 2.0;
      let height = mass * 16.0;
      place_block(&center, &(center + Vec3::new(0.0, height, 0.0)), radius, wood_color);
      center = center + Vec3::new(0.0, height, 0.0);
    }

    {
      let radius = mass * mass * 16.0;
      let height = mass * mass * 16.0;

      let mut points: Vec<Pnt3<_>> =
        range(0, (radius * radius * height / 8.0) as u32)
        .map(|_| {
          let x = rng.next_u32();
          let y = rng.next_u32();
          let z = rng.next_u32();
          Pnt3::new(
            fmod(x as f64, 2.0 * radius as f64) as f32 - radius,
            fmod(y as f64, height as f64) as f32,
            fmod(z as f64, 2.0 * radius as f64) as f32 - radius,
          )
        })
        .map(|p| p + *center.as_vec())
        .collect();

      let mut fringe = RingBuf::new();
      fringe.push_back(center);

      while let Some(p) = fringe.pop_front() {
        let mut i = 0;
        while i < points.len() {
          let &target = points.get(i).unwrap();
          if sqr_distance(&p, &target) <= 4.0*4.0 {
            if p.y < target.y {
              place_block(&p, &target, 0.2, wood_color);
            } else {
              place_block(&target, &p, 0.2, wood_color);
            }
            fringe.push_back(target);
            points.swap_remove(i);
          } else {
            i += 1;
          }
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>use nom::{Offset, AsBytes, Compare, CompareResult, InputLength, InputIter, Slice};
use std::ops::{Range, RangeFrom, RangeTo, RangeFull};
use inlinable_string::InlinableString;

#[macro_export]
macro_rules! slug {
    (__internal Done, $log:ident, $r:ident, ($rem:expr, $out:expr)) => {
        {
        use $crate::Compare;
        match $r {
            $crate::IResult::Done(rem, out) => {
                if rem.compare($rem) != $crate::CompareResult::Ok {
                    let expected: &str = $rem.into();
                    let found: &str = rem.into();
                    println!("expected {:?}, found {:?}", expected, found);
                    panic!();
                }
                if !out.eq(&$out) {
                    println!("different output: {:?} != {:?}", out, $out);
                    panic!();
                }
                println!("ok");
            },
            $crate::IResult::Error(e) => {
                println!("error: {:?}", e);
                panic!();
            },
            $crate::IResult::Incomplete(e) => {
                println!("incomplete: {:?}", e);
                panic!();
            }
        }

        }
    };

    (__internal Error, $log:ident, $r:ident, ) => {
        match $r {
            $crate::IResult::Done(_, _) => {
                println!("did not fail");
                panic!();
            },
            $crate::IResult::Error(_) => println!("ok"),
            nom::IResult::Incomplete(e) => {
                println!("incomplete: {:?}", e);
                panic!();
            }
        }
    };

    ( $(
        $parser:ident ($case:expr $(, $arg:expr)* ) => $d:tt $( ( $e:expr, $f:expr ) )* ;
        )* ) => {
        $(
            println!("{}({:?})", stringify!($parser), stringify!($case $(,$arg)*));

            let b = $crate::slug::wrap($case.into());
            let r = $parser(b.clone() $(,$arg)*);
            slug!(__internal $d, b, r, $( ($e, $f) )* );
        )*
    }
}

use std;
#[derive(Clone)]
pub struct Slug<'a> {
    // full input data
    data:           &'a str,

    // current slice
    slice:          &'a str,

    line:           usize
}
impl<'a> Slug<'a> {
    pub fn parse<F>(&self) -> Result<F, F::Err> where F: std::str::FromStr {
        self.slice.parse()
    }
    pub fn show(&self) {
        use std::iter::{repeat};

        // offset of slice into data
        let offset = self.slice.as_ptr() as usize - self.data.as_ptr() as usize;
        let line_start = self.data[.. offset]
            .rfind('\n')
            .map(|p| p+1)
            .unwrap_or_else(|| 0);
        let (line, endl) = match self.data[offset ..].find('\n') {
            Some(end) => (&self.data[line_start .. end+offset], '\u{21B5}'),
            None => (&self.data[line_start ..], '\u{2016}')
        };
        let cursor = self.data[line_start .. offset].chars().count();
        let marker: String = repeat(" ").take(cursor).collect();
        println!("line {}\n{}{}\n{}^ position", self.line, line, endl, marker);
    }
    pub fn len(&self) -> usize {
        self.slice.len()
    }
}
impl<'a> PartialEq for Slug<'a> {
    #[inline(always)]
    fn eq(&self, other: &Slug<'a>) -> bool {
        self.slice.eq(other.slice)
    }
}
impl<'a> PartialEq<str> for Slug<'a> {
    #[inline(always)]
    fn eq(&self, other: &str) -> bool {
        self.slice.eq(other)
    }
}
impl<'a, 'b> PartialEq<&'b str> for Slug<'a> {
    #[inline(always)]
    fn eq(&self, other: &&'b str) -> bool {
        self.slice.eq(*other)
    }
}
impl<'a> Into<&'a str> for Slug<'a> {
    #[inline(always)]
    fn into(self) -> &'a str {
        self.slice
    }
}
impl<'a> Into<String> for Slug<'a> {
    fn into(self) -> String {
        self.slice.to_owned()
    }
}
impl<'a> Into<InlinableString> for Slug<'a> {
    fn into(self) -> InlinableString {
        self.slice.into()
    }
}

impl<'a> std::fmt::Debug for Slug<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        self.slice.fmt(f)
    }
}

impl<'a> AsBytes for Slug<'a> {
    #[inline(always)]
    fn as_bytes(&self) -> &[u8] {
        self.data.as_bytes()
    }
}
impl<'a, 'b> Compare<&'b str> for Slug<'a> {
    #[inline(always)]
    fn compare(&self, o: &'b str) -> CompareResult {
        self.slice.compare(o)
    }

    #[inline(always)]
    fn compare_no_case(&self, o: &'b str) -> CompareResult {
        self.slice.compare_no_case(o)
    }
}
impl<'a> Slice<Range<usize>> for Slug<'a> {
    #[inline(always)]
    fn slice(&self, r: Range<usize>) -> Slug<'a> {
        let lines = self.slice[.. r.start].chars().filter(|&c| c == '\n').count();
        Slug {
            data:           self.data,
            slice:          self.slice.slice(r),
            line:           self.line + lines
        }
    }
}
impl<'a> Slice<RangeFrom<usize>> for Slug<'a> {
    #[inline(always)]
    fn slice(&self, r: RangeFrom<usize>) -> Slug<'a> {
        let lines = self.slice[.. r.start].chars().filter(|&c| c == '\n').count();
        Slug {
            data:           self.data,
            slice:          self.slice.slice(r),
            line:           self.line + lines
        }
    }
}
impl<'a> Slice<RangeTo<usize>> for Slug<'a> {
    #[inline(always)]
    fn slice(&self, r: RangeTo<usize>) -> Slug<'a> {
        Slug {
            data:           self.data,
            slice:          self.slice.slice(r),
            line:           self.line
        }
    }
}
impl<'a> Slice<RangeFull> for Slug<'a> {
    #[inline(always)]
    fn slice(&self, r: RangeFull) -> Slug<'a> {
        Slug {
            data:           self.data,
            slice:          self.slice,
            line:           self.line
        }
    }
}
impl<'a> Offset for Slug<'a> {
    #[inline(always)]
    fn offset(&self, second: &Slug) -> usize {
        let start = self.slice.as_ptr() as usize;
        let end = second.slice.as_ptr() as usize;

        assert!(end >= start, "negative offset");
        end - start
    }
}
impl<'a> InputLength for Slug<'a> {
    #[inline(always)]
    fn input_len(&self) -> usize {
        self.slice.len()
    }
}
impl<'a> InputIter for Slug<'a> {
    type Item     = char;
    type RawItem  = char;
    type Iter     = std::str::CharIndices<'a>;
    type IterElem = std::str::Chars<'a>;
    #[inline]
    fn iter_indices(&self) -> std::str::CharIndices<'a> {
        self.slice.char_indices()
    }
    #[inline]
    fn iter_elements(&self) -> std::str::Chars<'a> {
      self.slice.chars()
    }
    fn position<P>(&self, predicate: P) -> Option<usize> where P: Fn(Self::RawItem) -> bool {
      for (o,c) in self.slice.char_indices() {
        if predicate(c) {
          return Some(o)
        }
      }
      None
    }
    #[inline]
    fn slice_index(&self, count: usize) -> Option<usize> {
      let mut cnt    = 0;
      for (index, _) in self.slice.char_indices() {
        if cnt == count {
          return Some(index)
        }
        cnt += 1;
      }
      None
    }
}
pub fn wrap(data: &str) -> Slug {
    Slug {
        data:           data,
        slice:          data,
        line:           1
    }
}
<commit_msg>remove slug<commit_after><|endoftext|>