<commit_before>use std::char::from_u32;
use std::env;
use std::error;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::fs;
use std::io::Write;
use std::io;
use std::path::Path;
use std::process::{Command, Stdio, ExitStatus};
use std::str;
use std::thread;
use std::time::Duration;

use rand::random;

pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
                                                           callback: F)
                                                           -> io::Result<bool> {
    if !is_directory(path.as_ref()) {
        callback(path.as_ref());
        fs::create_dir_all(path.as_ref()).map(|()| true)
    } else {
        Ok(false)
    }
}

pub fn is_directory<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).ok().as_ref().map(fs::Metadata::is_dir) == Some(true)
}

pub fn is_file<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).ok().as_ref().map(fs::Metadata::is_file) == Some(true)
}

pub fn path_exists<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).is_ok()
}

pub fn random_string(length: usize) -> String {
    let chars = b"abcdefghijklmnopqrstuvwxyz0123456789_";
    (0..length).map(|_| from_u32(chars[random::<usize>() % chars.len()] as u32).unwrap()).collect()
}

pub fn if_not_empty<S: PartialEq<str>>(s: S) -> Option<S> {
    if s == *"" {
        None
    } else {
        Some(s)
    }
}

pub fn write_file(path: &Path, contents: &str) -> io::Result<()> {
    let mut file = try!(fs::OpenOptions::new()
                            .write(true)
                            .truncate(true)
                            .create(true)
                            .open(path));

    try!(io::Write::write_all(&mut file, contents.as_bytes()));

    try!(file.sync_data());

    Ok(())
}

pub fn read_file(path: &Path) -> io::Result<String> {
    let mut file = try!(fs::OpenOptions::new()
                            .read(true)
                            .open(path));

    let mut contents = String::new();

    try!(io::Read::read_to_string(&mut file, &mut contents));

    Ok(contents)
}

pub fn filter_file<F: FnMut(&str) -> bool>(src: &Path,
                                           dest: &Path,
                                           mut filter: F)
                                           -> io::Result<usize> {
    let src_file = try!(fs::File::open(src));
    let dest_file = try!(fs::File::create(dest));

    let mut reader = io::BufReader::new(src_file);
    let mut writer = io::BufWriter::new(dest_file);
    let mut removed = 0;

    for result in io::BufRead::lines(&mut reader) {
        let line = try!(result);
        if filter(&line) {
            try!(writeln!(&mut writer, "{}", &line));
        } else {
            removed += 1;
        }
    }

    try!(writer.flush());

    Ok(removed)
}

pub fn match_file<T, F: FnMut(&str) -> Option<T>>(src: &Path, mut f: F) -> io::Result<Option<T>> {
    let src_file = try!(fs::File::open(src));

    let mut reader = io::BufReader::new(src_file);

    for result in io::BufRead::lines(&mut reader) {
        let line = try!(result);
        if let Some(r) = f(&line) {
            return Ok(Some(r));
        }
    }

    Ok(None)
}

pub fn append_file(dest: &Path, line: &str) -> io::Result<()> {
    let mut dest_file = try!(fs::OpenOptions::new()
                                 .write(true)
                                 .append(true)
                                 .create(true)
                                 .open(dest));

    try!(writeln!(&mut dest_file, "{}", line));

    try!(dest_file.sync_data());

    Ok(())
}

pub fn tee_file<W: io::Write>(path: &Path, mut w: &mut W) -> io::Result<()> {
    let mut file = try!(fs::OpenOptions::new()
                            .read(true)
                            .open(path));

    let buffer_size = 0x10000;
    let mut buffer = vec![0u8; buffer_size];

    loop {
        let bytes_read = try!(io::Read::read(&mut file, &mut buffer));

        if bytes_read != 0 {
            try!(io::Write::write_all(w, &mut buffer[0..bytes_read]));
        } else {
            return Ok(());
        }
    }
}

pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
    #[cfg(windows)]
    fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
        // std's symlink uses Windows's symlink function, which requires
        // admin. We can create directory junctions the hard way without
        // though.
        symlink_junction_inner(src, dest)
    }
    #[cfg(not(windows))]
    fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
        ::std::os::unix::fs::symlink(src, dest)
    }

    let _ = remove_dir(dest);
    symlink_dir_inner(src, dest)
}

// Creating a directory junction on windows involves dealing with reparse
// points and the DeviceIoControl function, and this code is a skeleton of
// what can be found here:
//
// http://www.flexhex.com/docs/articles/hard-links.phtml
//
// Copied from std
#[cfg(windows)]
#[allow(non_snake_case)]
fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> {
    use winapi::*;
    use kernel32::*;
    use std::ptr;
    use std::os::windows::ffi::OsStrExt;

    const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024;

    #[repr(C)]
    pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
        pub ReparseTag: DWORD,
        pub ReparseDataLength: DWORD,
        pub Reserved: WORD,
        pub ReparseTargetLength: WORD,
        pub ReparseTargetMaximumLength: WORD,
        pub Reserved1: WORD,
        pub ReparseTarget: WCHAR,
    }

    fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
        fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
            let mut maybe_result: Vec<u16> = s.encode_wide().collect();
            if maybe_result.iter().any(|&u| u == 0) {
                return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                          "strings passed to WinAPI cannot contain NULs"));
            }
            maybe_result.push(0);
            Ok(maybe_result)
        }
        inner(s.as_ref())
    }

    // We're using low-level APIs to create the junction, and these are more picky about paths.
    // For example, forward slashes cannot be used as a path separator, so we should try to
    // canonicalize the path first.
    let target = try!(fs::canonicalize(target));

    try!(fs::create_dir(junction));

    let path = try!(to_u16s(junction));

    unsafe {
        let h = CreateFileW(path.as_ptr(),
                            GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            0 as *mut _,
                            OPEN_EXISTING,
                            FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
                            ptr::null_mut());

        let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
        let mut db = data.as_mut_ptr()
                        as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
        let buf = &mut (*db).ReparseTarget as *mut _;
        let mut i = 0;
        // FIXME: this conversion is very hacky
        let v = br"\??\";
        let v = v.iter().map(|x| *x as u16);
        for c in v.chain(target.as_os_str().encode_wide().skip(4)) {
            *buf.offset(i) = c;
            i += 1;
        }
        *buf.offset(i) = 0;
        i += 1;
        (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
        (*db).ReparseTargetMaximumLength = (i * 2) as WORD;
        (*db).ReparseTargetLength = ((i - 1) * 2) as WORD;
        (*db).ReparseDataLength =
                (*db).ReparseTargetLength as DWORD + 12;

        let mut ret = 0;
        let res = DeviceIoControl(h as *mut _,
                                  FSCTL_SET_REPARSE_POINT,
                                  data.as_ptr() as *mut _,
                                  (*db).ReparseDataLength + 8,
                                  ptr::null_mut(), 0,
                                  &mut ret,
                                  ptr::null_mut());

        if res == 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }
}

pub fn hardlink(src: &Path, dest: &Path) -> io::Result<()> {
    let _ = fs::remove_file(dest);
    fs::hard_link(src, dest)
}

#[derive(Debug)]
pub enum CommandError {
    Io(io::Error),
    Status(ExitStatus),
}

pub type CommandResult<T> = ::std::result::Result<T, CommandError>;

impl error::Error for CommandError {
    fn description(&self) -> &str {
        use self::CommandError::*;
        match *self {
            Io(_) => "could not execute command",
            Status(_) => "command exited with unsuccessful status",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        use self::CommandError::*;
        match *self {
            Io(ref e) => Some(e),
            Status(_) => None,
        }
    }
}

impl fmt::Display for CommandError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CommandError::Io(ref e) => write!(f, "Io: {}", e),
            CommandError::Status(ref s) => write!(f, "Status: {}", s),
        }
    }
}

pub fn cmd_status(cmd: &mut Command) -> CommandResult<()> {
    cmd.status().map_err(CommandError::Io).and_then(|s| {
        if s.success() {
            Ok(())
        } else {
            Err(CommandError::Status(s))
        }
    })
}

pub fn remove_dir(path: &Path) -> io::Result<()> {
    if try!(fs::symlink_metadata(path)).file_type().is_symlink() {
        if cfg!(windows) {
            fs::remove_dir(path)
        } else {
            fs::remove_file(path)
        }
    } else {
        // Again because remove_dir all doesn't delete write-only files on windows,
        // this is a custom implementation, more-or-less copied from cargo.
        // cc rust-lang/rust#31944
        // cc https://github.com/rust-lang/cargo/blob/master/tests/support/paths.rs#L52
        ::remove_dir_all::remove_dir_all(path)
    }
}

pub fn copy_dir(src: &Path, dest: &Path) -> io::Result<()> {
    try!(fs::create_dir(dest));
    for entry in try!(src.read_dir()) {
        let entry = try!(entry);
        let kind = try!(entry.file_type());
        let src = entry.path();
        let dest = dest.join(entry.file_name());
        if kind.is_dir() {
            try!(copy_dir(&src, &dest));
        } else {
            try!(fs::copy(&src, &dest));
        }
    }
    Ok(())
}

pub fn prefix_arg<S: AsRef<OsStr>>(name: &str, s: S) -> OsString {
    let mut arg = OsString::from(name);
    arg.push(s);
    arg
}

pub fn has_cmd(cmd: &str) -> bool {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    env::split_paths(&path).map(|p| {
        p.join(&cmd)
    }).any(|p| {
        p.exists()
    })
}

pub fn find_cmd<'a>(cmds: &[&'a str]) -> Option<&'a str> {
    cmds.into_iter().map(|&s| s).filter(|&s| has_cmd(s)).next()
}

pub fn open_browser(path: &Path) -> io::Result<bool> {
    #[cfg(not(windows))]
    fn inner(path: &Path) -> io::Result<bool> {
        let commands = ["xdg-open", "open", "firefox", "chromium"];
        if let Some(cmd) = find_cmd(&commands) {
            Command::new(cmd)
                .arg(path)
                .stdin(Stdio::null())
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .spawn()
                .map(|_| true)
        } else {
            Ok(false)
        }
    }
    #[cfg(windows)]
    fn inner(path: &Path) -> io::Result<bool> {
        Command::new("cmd")
            .arg("/C")
            .arg("start")
            .arg(path)
            .stdin(Stdio::null())
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .spawn()
            .map(|_| true)
    }
    inner(path)
}

#[cfg(windows)]
pub mod windows {
    use winapi::*;
    use std::io;
    use std::path::PathBuf;
    use std::ptr;
    use std::slice;
    use std::ffi::OsString;
    use std::os::windows::ffi::OsStringExt;
    use shell32;
    use ole32;

    #[allow(non_upper_case_globals)]
    pub const FOLDERID_LocalAppData: GUID = GUID {
        Data1: 0xF1B32785,
        Data2: 0x6FBA,
        Data3: 0x4FCF,
        Data4: [0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91],
    };
    #[allow(non_upper_case_globals)]
    pub const FOLDERID_Profile: GUID = GUID {
        Data1: 0x5E6C858F,
        Data2: 0x0E22,
        Data3: 0x4760,
        Data4: [0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73],
    };

    pub fn get_special_folder(id: &shtypes::KNOWNFOLDERID) -> io::Result<PathBuf> {

        let mut path = ptr::null_mut();
        let result;

        unsafe {
            let code = shell32::SHGetKnownFolderPath(id, 0, ptr::null_mut(), &mut path);
            if code == 0 {
                let mut length = 0usize;
                while *path.offset(length as isize) != 0 {
                    length += 1;
                }
                let slice = slice::from_raw_parts(path, length);
                result = Ok(OsString::from_wide(slice).into());
            } else {
                result = Err(io::Error::from_raw_os_error(code));
            }
            ole32::CoTaskMemFree(path as *mut _);
        }
        result
    }
}
<commit_msg>Auto merge of #1087 - jleedev:patch-1, r=brson<commit_after>use std::char::from_u32;
use std::env;
use std::error;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::fs;
use std::io::Write;
use std::io;
use std::path::Path;
use std::process::{Command, Stdio, ExitStatus};
use std::str;
use std::thread;
use std::time::Duration;

use rand::random;

pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
                                                           callback: F)
                                                           -> io::Result<bool> {
    if !is_directory(path.as_ref()) {
        callback(path.as_ref());
        fs::create_dir_all(path.as_ref()).map(|()| true)
    } else {
        Ok(false)
    }
}

pub fn is_directory<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).ok().as_ref().map(fs::Metadata::is_dir) == Some(true)
}

pub fn is_file<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).ok().as_ref().map(fs::Metadata::is_file) == Some(true)
}

pub fn path_exists<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).is_ok()
}

pub fn random_string(length: usize) -> String {
    let chars = b"abcdefghijklmnopqrstuvwxyz0123456789_";
    (0..length).map(|_| from_u32(chars[random::<usize>() % chars.len()] as u32).unwrap()).collect()
}

pub fn if_not_empty<S: PartialEq<str>>(s: S) -> Option<S> {
    if s == *"" {
        None
    } else {
        Some(s)
    }
}

pub fn write_file(path: &Path, contents: &str) -> io::Result<()> {
    let mut file = try!(fs::OpenOptions::new()
                            .write(true)
                            .truncate(true)
                            .create(true)
                            .open(path));

    try!(io::Write::write_all(&mut file, contents.as_bytes()));

    try!(file.sync_data());

    Ok(())
}

pub fn read_file(path: &Path) -> io::Result<String> {
    let mut file = try!(fs::OpenOptions::new()
                            .read(true)
                            .open(path));

    let mut contents = String::new();

    try!(io::Read::read_to_string(&mut file, &mut contents));

    Ok(contents)
}

pub fn filter_file<F: FnMut(&str) -> bool>(src: &Path,
                                           dest: &Path,
                                           mut filter: F)
                                           -> io::Result<usize> {
    let src_file = try!(fs::File::open(src));
    let dest_file = try!(fs::File::create(dest));

    let mut reader = io::BufReader::new(src_file);
    let mut writer = io::BufWriter::new(dest_file);
    let mut removed = 0;

    for result in io::BufRead::lines(&mut reader) {
        let line = try!(result);
        if filter(&line) {
            try!(writeln!(&mut writer, "{}", &line));
        } else {
            removed += 1;
        }
    }

    try!(writer.flush());

    Ok(removed)
}

pub fn match_file<T, F: FnMut(&str) -> Option<T>>(src: &Path, mut f: F) -> io::Result<Option<T>> {
    let src_file = try!(fs::File::open(src));

    let mut reader = io::BufReader::new(src_file);

    for result in io::BufRead::lines(&mut reader) {
        let line = try!(result);
        if let Some(r) = f(&line) {
            return Ok(Some(r));
        }
    }

    Ok(None)
}

pub fn append_file(dest: &Path, line: &str) -> io::Result<()> {
    let mut dest_file = try!(fs::OpenOptions::new()
                                 .write(true)
                                 .append(true)
                                 .create(true)
                                 .open(dest));

    try!(writeln!(&mut dest_file, "{}", line));

    try!(dest_file.sync_data());

    Ok(())
}

pub fn tee_file<W: io::Write>(path: &Path, mut w: &mut W) -> io::Result<()> {
    let mut file = try!(fs::OpenOptions::new()
                            .read(true)
                            .open(path));

    let buffer_size = 0x10000;
    let mut buffer = vec![0u8; buffer_size];

    loop {
        let bytes_read = try!(io::Read::read(&mut file, &mut buffer));

        if bytes_read != 0 {
            try!(io::Write::write_all(w, &mut buffer[0..bytes_read]));
        } else {
            return Ok(());
        }
    }
}

pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
    #[cfg(windows)]
    fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
        // std's symlink uses Windows's symlink function, which requires
        // admin. We can create directory junctions the hard way without
        // though.
        symlink_junction_inner(src, dest)
    }
    #[cfg(not(windows))]
    fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
        ::std::os::unix::fs::symlink(src, dest)
    }

    let _ = remove_dir(dest);
    symlink_dir_inner(src, dest)
}

// Creating a directory junction on windows involves dealing with reparse
// points and the DeviceIoControl function, and this code is a skeleton of
// what can be found here:
//
// http://www.flexhex.com/docs/articles/hard-links.phtml
//
// Copied from std
#[cfg(windows)]
#[allow(non_snake_case)]
fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> {
    use winapi::*;
    use kernel32::*;
    use std::ptr;
    use std::os::windows::ffi::OsStrExt;

    const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024;

    #[repr(C)]
    pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
        pub ReparseTag: DWORD,
        pub ReparseDataLength: DWORD,
        pub Reserved: WORD,
        pub ReparseTargetLength: WORD,
        pub ReparseTargetMaximumLength: WORD,
        pub Reserved1: WORD,
        pub ReparseTarget: WCHAR,
    }

    fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
        fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
            let mut maybe_result: Vec<u16> = s.encode_wide().collect();
            if maybe_result.iter().any(|&u| u == 0) {
                return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                          "strings passed to WinAPI cannot contain NULs"));
            }
            maybe_result.push(0);
            Ok(maybe_result)
        }
        inner(s.as_ref())
    }

    // We're using low-level APIs to create the junction, and these are more picky about paths.
    // For example, forward slashes cannot be used as a path separator, so we should try to
    // canonicalize the path first.
    let target = try!(fs::canonicalize(target));

    try!(fs::create_dir(junction));

    let path = try!(to_u16s(junction));

    unsafe {
        let h = CreateFileW(path.as_ptr(),
                            GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            0 as *mut _,
                            OPEN_EXISTING,
                            FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
                            ptr::null_mut());

        let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
        let mut db = data.as_mut_ptr()
                        as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
        let buf = &mut (*db).ReparseTarget as *mut _;
        let mut i = 0;
        // FIXME: this conversion is very hacky
        let v = br"\??\";
        let v = v.iter().map(|x| *x as u16);
        for c in v.chain(target.as_os_str().encode_wide().skip(4)) {
            *buf.offset(i) = c;
            i += 1;
        }
        *buf.offset(i) = 0;
        i += 1;
        (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
        (*db).ReparseTargetMaximumLength = (i * 2) as WORD;
        (*db).ReparseTargetLength = ((i - 1) * 2) as WORD;
        (*db).ReparseDataLength =
                (*db).ReparseTargetLength as DWORD + 12;

        let mut ret = 0;
        let res = DeviceIoControl(h as *mut _,
                                  FSCTL_SET_REPARSE_POINT,
                                  data.as_ptr() as *mut _,
                                  (*db).ReparseDataLength + 8,
                                  ptr::null_mut(), 0,
                                  &mut ret,
                                  ptr::null_mut());

        if res == 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }
}

pub fn hardlink(src: &Path, dest: &Path) -> io::Result<()> {
    let _ = fs::remove_file(dest);
    fs::hard_link(src, dest)
}

#[derive(Debug)]
pub enum CommandError {
    Io(io::Error),
    Status(ExitStatus),
}

pub type CommandResult<T> = ::std::result::Result<T, CommandError>;

impl error::Error for CommandError {
    fn description(&self) -> &str {
        use self::CommandError::*;
        match *self {
            Io(_) => "could not execute command",
            Status(_) => "command exited with unsuccessful status",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        use self::CommandError::*;
        match *self {
            Io(ref e) => Some(e),
            Status(_) => None,
        }
    }
}

impl fmt::Display for CommandError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CommandError::Io(ref e) => write!(f, "Io: {}", e),
            CommandError::Status(ref s) => write!(f, "Status: {}", s),
        }
    }
}

pub fn cmd_status(cmd: &mut Command) -> CommandResult<()> {
    cmd.status().map_err(CommandError::Io).and_then(|s| {
        if s.success() {
            Ok(())
        } else {
            Err(CommandError::Status(s))
        }
    })
}

pub fn remove_dir(path: &Path) -> io::Result<()> {
    if try!(fs::symlink_metadata(path)).file_type().is_symlink() {
        if cfg!(windows) {
            fs::remove_dir(path)
        } else {
            fs::remove_file(path)
        }
    } else {
        // Again because remove_dir all doesn't delete write-only files on windows,
        // this is a custom implementation, more-or-less copied from cargo.
        // cc rust-lang/rust#31944
        // cc https://github.com/rust-lang/cargo/blob/master/tests/support/paths.rs#L52
        ::remove_dir_all::remove_dir_all(path)
    }
}

pub fn copy_dir(src: &Path, dest: &Path) -> io::Result<()> {
    try!(fs::create_dir(dest));
    for entry in try!(src.read_dir()) {
        let entry = try!(entry);
        let kind = try!(entry.file_type());
        let src = entry.path();
        let dest = dest.join(entry.file_name());
        if kind.is_dir() {
            try!(copy_dir(&src, &dest));
        } else {
            try!(fs::copy(&src, &dest));
        }
    }
    Ok(())
}

pub fn prefix_arg<S: AsRef<OsStr>>(name: &str, s: S) -> OsString {
    let mut arg = OsString::from(name);
    arg.push(s);
    arg
}

pub fn has_cmd(cmd: &str) -> bool {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    env::split_paths(&path).map(|p| {
        p.join(&cmd)
    }).any(|p| {
        p.exists()
    })
}

pub fn find_cmd<'a>(cmds: &[&'a str]) -> Option<&'a str> {
    cmds.into_iter().map(|&s| s).filter(|&s| has_cmd(s)).next()
}

pub fn open_browser(path: &Path) -> io::Result<bool> {
    #[cfg(not(windows))]
    fn inner(path: &Path) -> io::Result<bool> {
        let commands = ["xdg-open", "open", "firefox", "chromium", "sensible-browser"];
        if let Some(cmd) = find_cmd(&commands) {
            Command::new(cmd)
                .arg(path)
                .stdin(Stdio::null())
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .spawn()
                .map(|_| true)
        } else {
            Ok(false)
        }
    }
    #[cfg(windows)]
    fn inner(path: &Path) -> io::Result<bool> {
        Command::new("cmd")
            .arg("/C")
            .arg("start")
            .arg(path)
            .stdin(Stdio::null())
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .spawn()
            .map(|_| true)
    }
    inner(path)
}

#[cfg(windows)]
pub mod windows {
    use winapi::*;
    use std::io;
    use std::path::PathBuf;
    use std::ptr;
    use std::slice;
    use std::ffi::OsString;
    use std::os::windows::ffi::OsStringExt;
    use shell32;
    use ole32;

    #[allow(non_upper_case_globals)]
    pub const FOLDERID_LocalAppData: GUID = GUID {
        Data1: 0xF1B32785,
        Data2: 0x6FBA,
        Data3: 0x4FCF,
        Data4: [0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91],
    };
    #[allow(non_upper_case_globals)]
    pub const FOLDERID_Profile: GUID = GUID {
        Data1: 0x5E6C858F,
        Data2: 0x0E22,
        Data3: 0x4760,
        Data4: [0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73],
    };

    pub fn get_special_folder(id: &shtypes::KNOWNFOLDERID) -> io::Result<PathBuf> {

        let mut path = ptr::null_mut();
        let result;

        unsafe {
            let code = shell32::SHGetKnownFolderPath(id, 0, ptr::null_mut(), &mut path);
            if code == 0 {
                let mut length = 0usize;
                while *path.offset(length as isize) != 0 {
                    length += 1;
                }
                let slice = slice::from_raw_parts(path, length);
                result = Ok(OsString::from_wide(slice).into());
            } else {
                result = Err(io::Error::from_raw_os_error(code));
            }
            ole32::CoTaskMemFree(path as *mut _);
        }
        result
    }
}
<|endoftext|>


<commit_before>use error::Result;
use failure::err_msg;

use html5ever::serialize::{serialize, SerializeOpts};
use html5ever::rcdom::{RcDom, NodeData, Handle};
use html5ever::driver::{parse_document, ParseOpts};
use html5ever::tendril::TendrilSink;

/// Extracts the contents of the `<head>` and `<body>` tags from an HTML document, as well as the
/// classes on the `<body>` tag, if any.
pub fn extract_head_and_body(html: &str) -> Result<(String, String, String)> {
    let parser = parse_document(RcDom::default(), ParseOpts::default());
    let dom = parser.one(html);

    let (head, body) = extract_from_rcdom(&dom)?;
    let class = extract_class(&body);

    Ok((stringify(head), stringify(body), class))
}

fn extract_from_rcdom(dom: &RcDom) -> Result<(Handle, Handle)> {
    let mut worklist = vec![dom.document.clone()];
    let (mut head, mut body) = (None, None);

    while let Some(handle) = worklist.pop() {
        match handle.data {
            NodeData::Element { ref name, .. } => match name.local.as_ref() {
                "head" => {
                    if head.is_some() {
                        return Err(err_msg("duplicate  tag"));
                    } else {
                        head = Some(handle.clone());
                    }
                }
                "body" => {
                    if body.is_some() {
                        return Err(err_msg("duplicate  tag"));
                    } else {
                        body = Some(handle.clone());
                    }
                }
                _ => {}  // do nothing
            }
            _ => {}  // do nothing
        }

        worklist.extend(handle.children.borrow().iter().cloned());
    }

    let head = head.ok_or_else(|| err_msg("couldn't find  tag in rustdoc output"))?;
    let body = body.ok_or_else(|| err_msg("couldn't find  tag in rustdoc output"))?;
    Ok((head, body))
}

fn stringify(node: Handle) -> String {
    let mut vec = Vec::new();
    serialize(&mut vec, &node, SerializeOpts::default())
        .expect("serializing into buffer failed");

    String::from_utf8(vec).expect("html5ever returned non-utf8 data")
}

fn extract_class(node: &Handle) -> String {
    match node.data {
        NodeData::Element { ref attrs, .. } => {
            let attrs = attrs.borrow();

            attrs.iter()
                 .find(|a| &a.name.local == "class")
                 .map_or(String::new(), |a| a.value.to_string())
        }
        _ => String::new()
    }
}

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

    fn round_trip(a: &str) -> String {
        let parser = parse_document(RcDom::default(), ParseOpts::default());
        stringify(parser.one(a).document)
    }
    fn mostly_equal(a: &str, b: &str) -> bool {
        round_trip(a.trim()).trim() == round_trip(b.trim()).trim()
    }

    #[test]
    fn small_html() {
        let (head, body, class) = super::extract_head_and_body(
            r#"<meta name="generator" content="rustdoc">
hello
"#
        ).unwrap();
        assert_eq!(head, r#"<meta name="generator" content="rustdoc">"#);
        assert_eq!(body, "
hello
");
        assert_eq!(class, "rustdoc struct");
    }

    // more of an integration test
    #[test]
    fn parse_regex_html() {
        let original = std::fs::read_to_string("benches/struct.CaptureMatches.html").unwrap();
        let expected_head = std::fs::read_to_string("tests/regex/head.html").unwrap();
        let expected_body = std::fs::read_to_string("tests/regex/body.html").unwrap();
        let (head, body, class) = super::extract_head_and_body(&original).unwrap();
        assert!(mostly_equal(&head, &expected_head));
        assert!(mostly_equal(&body, &expected_body));
        assert_eq!(class, "rustdoc struct");
    }
}
<commit_msg>Use exact comparisons instead of round-tripping through the parser<commit_after>use error::Result;
use failure::err_msg;

use html5ever::serialize::{serialize, SerializeOpts};
use html5ever::rcdom::{RcDom, NodeData, Handle};
use html5ever::driver::{parse_document, ParseOpts};
use html5ever::tendril::TendrilSink;

/// Extracts the contents of the `<head>` and `<body>` tags from an HTML document, as well as the
/// classes on the `<body>` tag, if any.
pub fn extract_head_and_body(html: &str) -> Result<(String, String, String)> {
    let parser = parse_document(RcDom::default(), ParseOpts::default());
    let dom = parser.one(html);

    let (head, body) = extract_from_rcdom(&dom)?;
    let class = extract_class(&body);

    Ok((stringify(head), stringify(body), class))
}

fn extract_from_rcdom(dom: &RcDom) -> Result<(Handle, Handle)> {
    let mut worklist = vec![dom.document.clone()];
    let (mut head, mut body) = (None, None);

    while let Some(handle) = worklist.pop() {
        match handle.data {
            NodeData::Element { ref name, .. } => match name.local.as_ref() {
                "head" => {
                    if head.is_some() {
                        return Err(err_msg("duplicate  tag"));
                    } else {
                        head = Some(handle.clone());
                    }
                }
                "body" => {
                    if body.is_some() {
                        return Err(err_msg("duplicate  tag"));
                    } else {
                        body = Some(handle.clone());
                    }
                }
                _ => {}  // do nothing
            }
            _ => {}  // do nothing
        }

        worklist.extend(handle.children.borrow().iter().cloned());
    }

    let head = head.ok_or_else(|| err_msg("couldn't find  tag in rustdoc output"))?;
    let body = body.ok_or_else(|| err_msg("couldn't find  tag in rustdoc output"))?;
    Ok((head, body))
}

fn stringify(node: Handle) -> String {
    let mut vec = Vec::new();
    serialize(&mut vec, &node, SerializeOpts::default())
        .expect("serializing into buffer failed");

    String::from_utf8(vec).expect("html5ever returned non-utf8 data")
}

fn extract_class(node: &Handle) -> String {
    match node.data {
        NodeData::Element { ref attrs, .. } => {
            let attrs = attrs.borrow();

            attrs.iter()
                 .find(|a| &a.name.local == "class")
                 .map_or(String::new(), |a| a.value.to_string())
        }
        _ => String::new()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn small_html() {
        let (head, body, class) = super::extract_head_and_body(
            r#"<meta name="generator" content="rustdoc">
hello
"#
        ).unwrap();
        assert_eq!(head, r#"<meta name="generator" content="rustdoc">"#);
        assert_eq!(body, "
hello
");
        assert_eq!(class, "rustdoc struct");
    }

    // more of an integration test
    #[test]
    fn parse_regex_html() {
        let original = std::fs::read_to_string("benches/struct.CaptureMatches.html").unwrap();
        let expected_head = std::fs::read_to_string("tests/regex/head.html").unwrap();
        let expected_body = std::fs::read_to_string("tests/regex/body.html").unwrap();
        let (head, body, class) = super::extract_head_and_body(&original).unwrap();
        assert_eq!(head, expected_head.trim());
        assert_eq!(&body, &expected_body.trim());
        assert_eq!(class, "rustdoc struct");
    }
}
<|endoftext|>


<commit_before>//! Work with spans of text.
//!
//! This module defines various structs describing a span of text from a
//! larger string.
use std::borrow::Cow;

/// A string with associated spans.
///
/// Each span has an associated attribute `T`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SpannedString<T> {
    source: String,
    spans: Vec<IndexedSpan<T>>,
}

impl<S, T> From<S> for SpannedString<T>
where
    S: Into<String>,
    T: Default,
{
    fn from(value: S) -> Self {
        Self::single_span(value.into(), T::default())
    }
}

impl<T> SpannedString<T> {
    /// Creates a new `SpannedString` manually.
    ///
    /// It is not recommended to use this directly.
    /// Instead, look for methods like `Markdown::parse`.
    pub fn new<S>(source: S, spans: Vec<IndexedSpan<T>>) -> Self
    where
        S: Into<String>,
    {
        let source = source.into();

        // Make sure the spans are within bounds.
        // This should disapear when compiled in release mode.
        for span in &spans {
            if let IndexedCow::Borrowed { end, .. } = span.content {
                assert!(end <= source.len());
            }
        }

        SpannedString { source, spans }
    }

    /// Returns a new SpannedString with a single span.
    pub fn single_span(source: String, attr: T) -> Self {
        let spans = vec![
            IndexedSpan {
                content: IndexedCow::Borrowed {
                    start: 0,
                    end: source.len(),
                },
                attr,
            },
        ];

        Self::new(source, spans)
    }

    /// Appends the given `StyledString` to `self`.
    pub fn append<S>(&mut self, other: S)
    where
        S: Into<Self>,
    {
        let other = other.into();
        self.append_raw(&other.source, other.spans);
    }

    /// Appends `content` and its corresponding spans to the end.
    ///
    /// It is not recommended to use this directly;
    /// instead, look at the `append` method.
    pub fn append_raw(&mut self, source: &str, spans: Vec<IndexedSpan<T>>) {
        let offset = self.source.len();
        let mut spans = spans;

        for span in &mut spans {
            span.content.offset(offset);
        }

        self.source.push_str(&source);
        self.spans.append(&mut spans);
    }

    /// Gives access to the parsed styled spans.
    pub fn spans<'a>(&'a self) -> Vec<Span<'a, T>> {
        self.spans
            .iter()
            .map(|span| span.resolve(&self.source))
            .collect()
    }

    /// Returns a reference to the indexed spans.
    pub fn spans_raw(&self) -> &[IndexedSpan<T>] {
        &self.spans
    }

    /// Returns a reference to the source string.
    ///
    /// This is the non-parsed string.
    pub fn source(&self) -> &str {
        &self.source
    }

    /// Returns `true` if self is empty.
    pub fn is_empty(&self) -> bool {
        self.source.is_empty() || self.spans.is_empty()
    }
}

/// An indexed span with an associated attribute.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IndexedSpan<T> {
    /// Content of the span.
    pub content: IndexedCow,

    /// Attribute applied to the span.
    pub attr: T,
}

/// A resolved span borrowing its source string.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Span<'a, T: 'a> {
    /// Content of this span.
    pub content: &'a str,

    /// Attribute associated to this span.
    pub attr: &'a T,
}

impl<T> IndexedSpan<T> {
    /// Resolve the span to a string slice and an attribute.
    pub fn resolve<'a>(&'a self, source: &'a str) -> Span<'a, T>
    where
        T: 'a,
    {
        Span {
            content: self.content.resolve(source),
            attr: &self.attr,
        }
    }

    /// Returns `true` if `self` is an empty span.
    pub fn is_empty(&self) -> bool {
        self.content.is_empty()
    }
}

/// A span of text that can be either owned, or indexed in another String.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IndexedCow {
    /// Indexes content in a separate string.
    Borrowed {
        /// Byte offset of the beginning of the span (inclusive)
        start: usize,

        /// Byte offset of the end of the span (exclusive)
        end: usize,
    },

    /// Owns its content.
    Owned(String),
}

impl IndexedCow {
    /// Resolve the span to a string slice.
    pub fn resolve<'a>(&'a self, source: &'a str) -> &'a str {
        match *self {
            IndexedCow::Borrowed { start, end } => &source[start..end],
            IndexedCow::Owned(ref content) => content,
        }
    }

    /// Returns an indexed view of the given item.
    ///
    /// **Note**: it is assumed `cow`, if borrowed, is a substring of `source`.
    pub fn from_cow(cow: Cow<str>, source: &str) -> Self {
        match cow {
            Cow::Owned(value) => IndexedCow::Owned(value),
            Cow::Borrowed(value) => {
                let source_pos = source.as_ptr() as usize;
                let value_pos = value.as_ptr() as usize;

                // Make sure `value` is indeed a substring of `source`
                assert!(value_pos >= source_pos);
                assert!(value_pos + value.len() <= source_pos + source.len());
                let start = value_pos - source_pos;
                let end = start + value.len();

                IndexedCow::Borrowed { start, end }
            }
        }
    }

    /// Returns `ŧrue` if this represents an empty span.
    pub fn is_empty(&self) -> bool {
        match *self {
            IndexedCow::Borrowed { start, end } => start == end,
            IndexedCow::Owned(ref content) => content.is_empty(),
        }
    }

    /// If `self` is borrowed, offset its indices by the given value.
    ///
    /// Useful to update spans when concatenating sources.
    pub fn offset(&mut self, offset: usize) {
        if let IndexedCow::Borrowed {
            ref mut start,
            ref mut end,
        } = *self
        {
            *start += offset;
            *end += offset;
        }
    }
}
<commit_msg>Fix more clippy warnings<commit_after>//! Work with spans of text.
//!
//! This module defines various structs describing a span of text from a
//! larger string.
use std::borrow::Cow;

/// A string with associated spans.
///
/// Each span has an associated attribute `T`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SpannedString<T> {
    source: String,
    spans: Vec<IndexedSpan<T>>,
}

impl<S, T> From<S> for SpannedString<T>
where
    S: Into<String>,
    T: Default,
{
    fn from(value: S) -> Self {
        Self::single_span(value.into(), T::default())
    }
}

impl<T> SpannedString<T> {
    /// Creates a new `SpannedString` manually.
    ///
    /// It is not recommended to use this directly.
    /// Instead, look for methods like `Markdown::parse`.
    pub fn new<S>(source: S, spans: Vec<IndexedSpan<T>>) -> Self
    where
        S: Into<String>,
    {
        let source = source.into();

        // Make sure the spans are within bounds.
        // This should disapear when compiled in release mode.
        for span in &spans {
            if let IndexedCow::Borrowed { end, .. } = span.content {
                assert!(end <= source.len());
            }
        }

        SpannedString { source, spans }
    }

    /// Returns a new SpannedString with a single span.
    pub fn single_span(source: String, attr: T) -> Self {
        let spans = vec![
            IndexedSpan {
                content: IndexedCow::Borrowed {
                    start: 0,
                    end: source.len(),
                },
                attr,
            },
        ];

        Self::new(source, spans)
    }

    /// Appends the given `StyledString` to `self`.
    pub fn append<S>(&mut self, other: S)
    where
        S: Into<Self>,
    {
        let other = other.into();
        self.append_raw(&other.source, other.spans);
    }

    /// Appends `content` and its corresponding spans to the end.
    ///
    /// It is not recommended to use this directly;
    /// instead, look at the `append` method.
    pub fn append_raw(&mut self, source: &str, spans: Vec<IndexedSpan<T>>) {
        let offset = self.source.len();
        let mut spans = spans;

        for span in &mut spans {
            span.content.offset(offset);
        }

        self.source.push_str(source);
        self.spans.append(&mut spans);
    }

    /// Gives access to the parsed styled spans.
    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
    pub fn spans<'a>(&'a self) -> Vec<Span<'a, T>> {
        self.spans
            .iter()
            .map(|span| span.resolve(&self.source))
            .collect()
    }

    /// Returns a reference to the indexed spans.
    pub fn spans_raw(&self) -> &[IndexedSpan<T>] {
        &self.spans
    }

    /// Returns a reference to the source string.
    ///
    /// This is the non-parsed string.
    pub fn source(&self) -> &str {
        &self.source
    }

    /// Returns `true` if self is empty.
    pub fn is_empty(&self) -> bool {
        self.source.is_empty() || self.spans.is_empty()
    }
}

/// An indexed span with an associated attribute.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IndexedSpan<T> {
    /// Content of the span.
    pub content: IndexedCow,

    /// Attribute applied to the span.
    pub attr: T,
}

/// A resolved span borrowing its source string.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Span<'a, T: 'a> {
    /// Content of this span.
    pub content: &'a str,

    /// Attribute associated to this span.
    pub attr: &'a T,
}

impl<T> IndexedSpan<T> {
    /// Resolve the span to a string slice and an attribute.
    pub fn resolve<'a>(&'a self, source: &'a str) -> Span<'a, T>
    where
        T: 'a,
    {
        Span {
            content: self.content.resolve(source),
            attr: &self.attr,
        }
    }

    /// Returns `true` if `self` is an empty span.
    pub fn is_empty(&self) -> bool {
        self.content.is_empty()
    }
}

/// A span of text that can be either owned, or indexed in another String.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IndexedCow {
    /// Indexes content in a separate string.
    Borrowed {
        /// Byte offset of the beginning of the span (inclusive)
        start: usize,

        /// Byte offset of the end of the span (exclusive)
        end: usize,
    },

    /// Owns its content.
    Owned(String),
}

impl IndexedCow {
    /// Resolve the span to a string slice.
    pub fn resolve<'a>(&'a self, source: &'a str) -> &'a str {
        match *self {
            IndexedCow::Borrowed { start, end } => &source[start..end],
            IndexedCow::Owned(ref content) => content,
        }
    }

    /// Returns an indexed view of the given item.
    ///
    /// **Note**: it is assumed `cow`, if borrowed, is a substring of `source`.
    pub fn from_cow(cow: Cow<str>, source: &str) -> Self {
        match cow {
            Cow::Owned(value) => IndexedCow::Owned(value),
            Cow::Borrowed(value) => {
                let source_pos = source.as_ptr() as usize;
                let value_pos = value.as_ptr() as usize;

                // Make sure `value` is indeed a substring of `source`
                assert!(value_pos >= source_pos);
                assert!(value_pos + value.len() <= source_pos + source.len());
                let start = value_pos - source_pos;
                let end = start + value.len();

                IndexedCow::Borrowed { start, end }
            }
        }
    }

    /// Returns `ŧrue` if this represents an empty span.
    pub fn is_empty(&self) -> bool {
        match *self {
            IndexedCow::Borrowed { start, end } => start == end,
            IndexedCow::Owned(ref content) => content.is_empty(),
        }
    }

    /// If `self` is borrowed, offset its indices by the given value.
    ///
    /// Useful to update spans when concatenating sources.
    pub fn offset(&mut self, offset: usize) {
        if let IndexedCow::Borrowed {
            ref mut start,
            ref mut end,
        } = *self
        {
            *start += offset;
            *end += offset;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::ptr::Unique;
use core::fmt;
use spin::Mutex;
use volatile::Volatile;

const BUFFER_HEIGHT: usize = 25;
const BUFFER_WIDTH: usize = 80;

pub static WRITER: Mutex<Writer> = Mutex::new(Writer {
    column_position: 0,
    color_code: ColorCode::new(Color::LightGreen, Color::Black),
    buffer: unsafe { Unique::new(0xb8000 as *mut _) },
});

macro_rules! println {
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

macro_rules! print {
    ($($arg:tt)*) => ({
            $crate::vga_buffer::print(format_args!($($arg)*));
    });
}

pub fn print(args: fmt::Arguments) {
    use core::fmt::Write;
    WRITER.lock().write_fmt(args).unwrap();
}

pub fn clear_screen() {
    for _ in 0..BUFFER_HEIGHT {
        println!("");
    }
}

#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum Color {
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Magenta = 5,
    Brown = 6,
    LightGray = 7,
    DarkGray = 8,
    LightBlue = 9,
    LightGreen = 10,
    LightCyan = 11,
    LightRed = 12,
    Pink = 13,
    Yellow = 14,
    White = 15,
}

pub struct Writer {
    column_position: usize,
    color_code: ColorCode,
    buffer: Unique<Buffer>,
}

impl Writer {
    pub fn write_byte(&mut self, byte: u8) {
        match byte {
            b'\n' => self.new_line(),
            byte => {
                if self.column_position >= BUFFER_WIDTH {
                    self.new_line();
                }
                let row = BUFFER_HEIGHT - 1;
                let col = self.column_position;

                let color_code = self.color_code;

                self.buffer().chars[row][col].write(ScreenChar {
                    ascii_character: byte,
                    color_code: color_code,
                });
                self.column_position += 1;
            }
        }
    }

    fn buffer(&mut self) -> &mut Buffer {
        unsafe { self.buffer.get_mut() }
    }

    fn new_line(&mut self) {
        for row in 1..BUFFER_HEIGHT {
            for col in 0..BUFFER_WIDTH {
                let buffer = self.buffer();
                let character = buffer.chars[row][col].read();
                buffer.chars[row - 1][col].write(character);
            }
        }
        self.clear_row(BUFFER_HEIGHT - 1);
        self.column_position = 0;
    }

    fn clear_row(&mut self, row: usize) {
        let blank = ScreenChar {
            ascii_character: b' ',
            color_code: self.color_code,
        };
        for col in 0..BUFFER_WIDTH {
            self.buffer().chars[row][col].write(blank);
        }
    }
}

impl fmt::Write for Writer {
    fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
        for byte in s.bytes() {
            self.write_byte(byte)
        }
        Ok(())
    }
}

#[derive(Debug, Clone, Copy)]
struct ColorCode(u8);

impl ColorCode {
    const fn new(foreground: Color, background: Color) -> ColorCode {
        ColorCode((background as u8) << 4 | (foreground as u8))
    }
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct ScreenChar {
    ascii_character: u8,
    color_code: ColorCode,
}

struct Buffer {
    chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
<commit_msg>Implement scroll on the VGA console<commit_after>//! # VGA Console Implementation

use core::ptr::Unique;
use core::fmt;
use spin::Mutex;
use volatile::Volatile;

// macros definition
macro_rules! println {
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

macro_rules! print {
    ($($arg:tt)*) => ({
            $crate::vga_buffer::print(format_args!($($arg)*));
    });
}

// VGA screen dimentions
const BUFFER_HEIGHT: usize = 25;
const BUFFER_WIDTH: usize = 80;

#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum Color {
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Magenta = 5,
    Brown = 6,
    LightGray = 7,
    DarkGray = 8,
    LightBlue = 9,
    LightGreen = 10,
    LightCyan = 11,
    LightRed = 12,
    Pink = 13,
    Yellow = 14,
    White = 15,
}

#[derive(Debug, Clone, Copy)]
struct ColorCode(u8);

impl ColorCode {
    const fn new(foreground: Color, background: Color) -> ColorCode {
        ColorCode((background as u8) << 4 | (foreground as u8))
    }
}

pub struct Writer {
    row_positon: usize,
    column_position: usize,
    color_code: ColorCode,
    buffer: Unique<Buffer>,
}

pub static WRITER: Mutex<Writer> = Mutex::new(Writer {
    row_positon: 0,
    column_position: 0,
    color_code: ColorCode::new(Color::Cyan, Color::White),
    buffer: unsafe { Unique::new(0xb8000 as *mut _) },
});

/// Implement the Writer Struct
impl Writer {

    /// Write a byte to the console.
    ///
    /// # Arguments
    ///
    /// * `byte` - Byte to be writen
    pub fn write_byte(&mut self, byte: u8) {
        match byte {
            b'\n' => self.new_line(),
            byte => {
                if self.column_position >= BUFFER_WIDTH {
                    self.new_line();
                }
                let row = self.row_positon;
                let col = self.column_position;

                let color_code = self.color_code;

                self.buffer().chars[row][col].write(ScreenChar {
                    ascii_character: byte,
                    color_code: color_code,
                });
                self.column_position += 1;
            }
        }
    }

    /// Gets a mutable reference to the console Buffer.
    fn buffer(&mut self) -> &mut Buffer {
        unsafe { self.buffer.get_mut() }
    }

    /// Adds a new file
    fn new_line(&mut self) {
        // increment the current row
        self.row_positon += 1;

        // reset the column positon
        self.column_position = 0;

        // scroll the view if there is no more free rows
        if self.row_positon == BUFFER_HEIGHT {
            for row in 1..BUFFER_HEIGHT {
                for col in 0..BUFFER_WIDTH {
                    let buffer = self.buffer();
                    let character = buffer.chars[row][col].read();
                    buffer.chars[row - 1][col].write(character);
                }
            }

            // clear the last row
            self.clear_row(BUFFER_HEIGHT - 1);

            // positon the cursor on the last row
            self.row_positon -= 1;
        }
    }

    /// Clear a full row
    fn clear_row(&mut self, row: usize) {
        let blank = ScreenChar {
            ascii_character: b' ',
            color_code: self.color_code,
        };
        for col in 0..BUFFER_WIDTH {
            self.buffer().chars[row][col].write(blank);
        }
    }
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct ScreenChar {
    ascii_character: u8,
    color_code: ColorCode,
}

struct Buffer {
    chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}

pub fn print(args: fmt::Arguments) {
    use core::fmt::Write;
    WRITER.lock().write_fmt(args).unwrap();
}

/// Clear screen-
pub fn clear_screen() {
    // iterate all rows and clear them all
    for i in 0..BUFFER_HEIGHT {
        WRITER.lock().clear_row(i);
    }

    // reset the row position
    WRITER.lock().row_positon = 0;
}

impl fmt::Write for Writer {
    fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
        for byte in s.bytes() {
            self.write_byte(byte)
        }
        Ok(())
    }
}

extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u32) -> ! {
    loop {}
}
<|endoftext|>


<commit_before>//! LDAP Client Crate
//!
//! This crate serves as opinionated abstractions over `ldap_protocol`.
//! While it is useful for LDAP clients it will not work well as LDAP Server.

// TODO: Make this a deny.
#![warn(missing_docs)]

#[doc(no_inline)]
extern crate ldap_protocol as protocol;

use std::net::TcpStream;
use std::net::ToSocketAddrs;

use std::io::{Read, Write};

use protocol::ber::{self, common};
use protocol::Result;

pub mod bind;

/// Core LDAP struct
///
/// This struct contains all state of the LDAP connection this crate establishes.
/// It is used in all LDAP functions.
#[derive(Debug)]
pub struct LDAP
{
    // TODO: Later abstract over io::Read / io::Write
    stream: TcpStream,

    msgid: i32,
}

impl LDAP
{

    /// Connect to the LDAP-Server found at `addr` using plain unencrypted TLS
    pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<LDAP>
    {
        let stream = try!(TcpStream::connect(addr));

        Ok(LDAP
        {
            stream: stream,
            msgid: 0,
        })
    }

    fn send(&mut self, tag: common::Tag) -> Result<()>
    {
        println!("Sending tag: {:?}", tag);
        let tagbuf = try!(ber::encode(tag, self.msgid));
        try!(self.stream.write(tagbuf.as_slice()));

        Ok(())
    }

    fn recv(&mut self) -> Result<common::Tag>
    {
        let mut buf = [0; 500];

        let readamount = try!(self.stream.read(&mut buf));
        println!("read: {}", readamount);

        let tag = try!(ber::decode(&mut buf));
        println!("Received tag: {:?}", tag);

        Ok(tag)
    }
}
<commit_msg>Make recv temporarily public<commit_after>//! LDAP Client Crate
//!
//! This crate serves as opinionated abstractions over `ldap_protocol`.
//! While it is useful for LDAP clients it will not work well as LDAP Server.

// TODO: Make this a deny.
#![warn(missing_docs)]

#[doc(no_inline)]
extern crate ldap_protocol as protocol;

use std::net::TcpStream;
use std::net::ToSocketAddrs;

use std::io::{Read, Write};

use protocol::ber::{self, common};
pub use protocol::Result;

pub mod bind;

/// Core LDAP struct
///
/// This struct contains all state of the LDAP connection this crate establishes.
/// It is used in all LDAP functions.
#[derive(Debug)]
pub struct LDAP
{
    // TODO: Later abstract over io::Read / io::Write
    stream: TcpStream,

    msgid: i32,
}

impl LDAP
{

    /// Connect to the LDAP-Server found at `addr` using plain unencrypted TLS
    pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<LDAP>
    {
        let stream = try!(TcpStream::connect(addr));

        Ok(LDAP
        {
            stream: stream,
            msgid: 0,
        })
    }

    fn send(&mut self, tag: common::Tag) -> Result<()>
    {
        println!("Sending tag: {:?}", tag);
        let tagbuf = try!(ber::encode(tag, self.msgid));
        try!(self.stream.write(tagbuf.as_slice()));

        Ok(())
    }

    pub fn recv(&mut self) -> Result<common::Tag>
    {
        let mut buf = [0; 500];

        let readamount = try!(self.stream.read(&mut buf));
        println!("read: {}", readamount);

        let tag = try!(ber::decode(&mut buf));
        println!("Received tag: {:?}", tag);

        Ok(tag)
    }
}
<|endoftext|>


<commit_before>use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Read, Seek, SeekFrom};
use std::mem::size_of;
use std::string::{FromUtf16Error, FromUtf8Error};

use stream::Event;
use {u64_to_usize, Date, Error};

impl From<FromUtf8Error> for Error {
    fn from(_: FromUtf8Error) -> Error {
        Error::InvalidData
    }
}

impl From<FromUtf16Error> for Error {
    fn from(_: FromUtf16Error) -> Error {
        Error::InvalidData
    }
}

struct StackItem {
    object_ref: u64,
    child_object_refs: Vec<u64>,
    ty: StackType,
}

enum StackType {
    Array,
    Dict,
}

// https://opensource.apple.com/source/CF/CF-550/CFBinaryPList.c
// https://hg.python.org/cpython/file/3.4/Lib/plistlib.py
pub struct BinaryReader<R> {
    stack: Vec<StackItem>,
    object_offsets: Vec<u64>,
    object_on_stack: Vec<bool>,
    reader: R,
    ref_size: u8,
    root_object: u64,
    // The largest single allocation allowed for this plist.
    // Equal to the number of bytes in the plist minus the magic number and trailer.
    max_allocation_bytes: usize,
}

impl<R: Read + Seek> BinaryReader<R> {
    pub fn new(reader: R) -> BinaryReader<R> {
        BinaryReader {
            stack: Vec::new(),
            object_offsets: Vec::new(),
            object_on_stack: Vec::new(),
            reader,
            ref_size: 0,
            root_object: 0,
            max_allocation_bytes: 0,
        }
    }

    fn can_allocate(&self, len: u64, size: usize) -> bool {
        let byte_len = len.saturating_mul(size as u64);
        byte_len <= self.max_allocation_bytes as u64
    }

    fn allocate_vec<T>(&self, len: u64, size: usize) -> Result<Vec<T>, Error> {
        if self.can_allocate(len, size) {
            Ok(Vec::with_capacity(len as usize))
        } else {
            Err(Error::InvalidData)
        }
    }

    fn read_trailer(&mut self) -> Result<(), Error> {
        self.reader.seek(SeekFrom::Start(0))?;
        let mut magic = [0; 8];
        self.reader.read_exact(&mut magic)?;
        if &magic != b"bplist00" {
            return Err(Error::InvalidData);
        }

        // Trailer starts with 6 bytes of padding
        let trailer_start = self.reader.seek(SeekFrom::End(-32 + 6))?;

        let offset_size = self.reader.read_u8()?;
        match offset_size {
            1 | 2 | 4 | 8 => (),
            _ => return Err(Error::InvalidData),
        }

        self.ref_size = self.reader.read_u8()?;
        match self.ref_size {
            1 | 2 | 4 | 8 => (),
            _ => return Err(Error::InvalidData),
        }

        let num_objects = self.reader.read_u64::<BigEndian>()?;
        self.root_object = self.reader.read_u64::<BigEndian>()?;
        let offset_table_offset = self.reader.read_u64::<BigEndian>()?;

        // File size minus trailer and header
        // Truncated to max(usize)
        self.max_allocation_bytes = trailer_start.saturating_sub(8) as usize;

        // Read offset table
        self.reader.seek(SeekFrom::Start(offset_table_offset))?;
        self.object_offsets = self.read_ints(num_objects, offset_size)?;
        self.object_on_stack = vec![false; self.object_offsets.len()];

        Ok(())
    }

    fn read_ints(&mut self, len: u64, size: u8) -> Result<Vec<u64>, Error> {
        let mut ints = self.allocate_vec(len, size as usize)?;
        for _ in 0..len {
            match size {
                1 => ints.push(self.reader.read_u8()?.into()),
                2 => ints.push(self.reader.read_u16::<BigEndian>()?.into()),
                4 => ints.push(self.reader.read_u32::<BigEndian>()?.into()),
                8 => ints.push(self.reader.read_u64::<BigEndian>()?),
                _ => return Err(Error::InvalidData),
            }
        }
        Ok(ints)
    }

    fn read_refs(&mut self, len: u64) -> Result<Vec<u64>, Error> {
        let ref_size = self.ref_size;
        self.read_ints(len, ref_size)
    }

    fn read_object_len(&mut self, len: u8) -> Result<u64, Error> {
        if (len & 0x0f) == 0x0f {
            let len_power_of_two = self.reader.read_u8()? & 0x03;
            Ok(match len_power_of_two {
                0 => self.reader.read_u8()?.into(),
                1 => self.reader.read_u16::<BigEndian>()?.into(),
                2 => self.reader.read_u32::<BigEndian>()?.into(),
                3 => self.reader.read_u64::<BigEndian>()?,
                _ => return Err(Error::InvalidData),
            })
        } else {
            Ok(len.into())
        }
    }

    fn read_data(&mut self, len: u64) -> Result<Vec<u8>, Error> {
        let mut data = self.allocate_vec(len, size_of::<u8>())?;
        data.resize(len as usize, 0);
        self.reader.read_exact(&mut data)?;
        Ok(data)
    }

    fn seek_to_object(&mut self, object_ref: u64) -> Result<u64, Error> {
        let object_ref = u64_to_usize(object_ref).ok_or(Error::InvalidData)?;
        let offset = *self
            .object_offsets
            .get(object_ref)
            .ok_or(Error::InvalidData)?;
        Ok(self.reader.seek(SeekFrom::Start(offset))?)
    }

    fn push_stack_item_and_check_for_recursion(&mut self, item: StackItem) -> Result<(), Error> {
        let object_ref = u64_to_usize(item.object_ref).expect("internal consistency error");
        let is_on_stack = &mut self.object_on_stack[object_ref];
        if *is_on_stack {
            return Err(Error::InvalidData);
        }
        *is_on_stack = true;
        self.stack.push(item);
        Ok(())
    }

    fn pop_stack_item(&mut self) -> StackItem {
        let item = self.stack.pop().expect("internal consistency error");
        let object_ref = u64_to_usize(item.object_ref).expect("internal consistency error");
        self.object_on_stack[object_ref] = false;
        item
    }

    fn read_next(&mut self) -> Result<Option<Event>, Error> {
        let object_ref = if self.ref_size == 0 {
            // Initialise here rather than in new
            self.read_trailer()?;
            self.root_object
        } else {
            let maybe_object_ref = if let Some(stack_item) = self.stack.last_mut() {
                stack_item.child_object_refs.pop()
            } else {
                // Finished reading the plist
                return Ok(None);
            };

            if let Some(object_ref) = maybe_object_ref {
                object_ref
            } else {
                // We're at the end of an array or dict. Pop the top stack item and return.
                let stack_item = self.pop_stack_item();
                match stack_item.ty {
                    StackType::Array => return Ok(Some(Event::EndArray)),
                    StackType::Dict => return Ok(Some(Event::EndDictionary)),
                }
            }
        };

        self.seek_to_object(object_ref)?;

        let token = self.reader.read_u8()?;
        let ty = (token & 0xf0) >> 4;
        let size = token & 0x0f;

        let result = match (ty, size) {
            (0x0, 0x00) => return Err(Error::InvalidData), // null
            (0x0, 0x08) => Some(Event::Boolean(false)),
            (0x0, 0x09) => Some(Event::Boolean(true)),
            (0x0, 0x0f) => return Err(Error::InvalidData), // fill
            (0x1, 0) => Some(Event::Integer(self.reader.read_u8()?.into())),
            (0x1, 1) => Some(Event::Integer(self.reader.read_u16::<BigEndian>()?.into())),
            (0x1, 2) => Some(Event::Integer(self.reader.read_u32::<BigEndian>()?.into())),
            (0x1, 3) => Some(Event::Integer(self.reader.read_i64::<BigEndian>()?.into())),
            (0x1, 4) => {
                let value = self.reader.read_i128::<BigEndian>()?;
                if value < 0 || value > u64::max_value().into() {
                    return Err(Error::InvalidData);
                }
                Some(Event::Integer((value as u64).into()))
            }
            (0x1, _) => return Err(Error::InvalidData), // variable length int
            (0x2, 2) => Some(Event::Real(self.reader.read_f32::<BigEndian>()?.into())),
            (0x2, 3) => Some(Event::Real(self.reader.read_f64::<BigEndian>()?)),
            (0x2, _) => return Err(Error::InvalidData), // odd length float
            (0x3, 3) => {
                // Date. Seconds since 1/1/2001 00:00:00.
                let secs = self.reader.read_f64::<BigEndian>()?;
                Some(Event::Date(
                    Date::from_seconds_since_plist_epoch(secs).map_err(|()| Error::InvalidData)?,
                ))
            }
            (0x4, n) => {
                // Data
                let len = self.read_object_len(n)?;
                Some(Event::Data(self.read_data(len)?))
            }
            (0x5, n) => {
                // ASCII string
                let len = self.read_object_len(n)?;
                let raw = self.read_data(len)?;
                let string = String::from_utf8(raw)?;
                Some(Event::String(string))
            }
            (0x6, n) => {
                // UTF-16 string
                let len_utf16_codepoints = self.read_object_len(n)?;
                let mut raw_utf16 = self.allocate_vec(len_utf16_codepoints, size_of::<u16>())?;

                for _ in 0..len_utf16_codepoints {
                    raw_utf16.push(self.reader.read_u16::<BigEndian>()?);
                }

                let string = String::from_utf16(&raw_utf16)?;
                Some(Event::String(string))
            }
            (0xa, n) => {
                // Array
                let len = self.read_object_len(n)?;
                let mut child_object_refs = self.read_refs(len)?;
                // Reverse so we can pop off the end of the stack in order
                child_object_refs.reverse();

                self.push_stack_item_and_check_for_recursion(StackItem {
                    object_ref,
                    ty: StackType::Array,
                    child_object_refs,
                })?;

                Some(Event::StartArray(Some(len)))
            }
            (0xd, n) => {
                // Dict
                let len = self.read_object_len(n)?;
                let key_refs = self.read_refs(len)?;
                let value_refs = self.read_refs(len)?;

                let mut child_object_refs = self.allocate_vec(len * 2, self.ref_size as usize)?;
                let len = key_refs.len();
                for i in 1..len + 1 {
                    // Reverse so we can pop off the end of the stack in order
                    child_object_refs.push(value_refs[len - i]);
                    child_object_refs.push(key_refs[len - i]);
                }

                self.push_stack_item_and_check_for_recursion(StackItem {
                    object_ref,
                    ty: StackType::Dict,
                    child_object_refs,
                })?;

                Some(Event::StartDictionary(Some(len as u64)))
            }
            (_, _) => return Err(Error::InvalidData),
        };

        Ok(result)
    }
}

impl<R: Read + Seek> Iterator for BinaryReader<R> {
    type Item = Result<Event, Error>;

    fn next(&mut self) -> Option<Result<Event, Error>> {
        match self.read_next() {
            Ok(Some(event)) => Some(Ok(event)),
            Err(err) => {
                // Mark the plist as finished
                self.stack.clear();
                Some(Err(err))
            }
            Ok(None) => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use humantime::parse_rfc3339_weak;
    use std::fs::File;
    use std::path::Path;

    use super::*;
    use stream::Event;
    use stream::Event::*;

    #[test]
    fn streaming_parser() {
        let reader = File::open(&Path::new("./tests/data/binary.plist")).unwrap();
        let streaming_parser = BinaryReader::new(reader);
        let events: Vec<Event> = streaming_parser.map(|e| e.unwrap()).collect();

        let comparison = &[
            StartDictionary(Some(9)),
            String("Author".into()),
            String("William Shakespeare".into()),
            String("Height".into()),
            Real(1.6),
            String("Data".into()),
            Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]),
            String("Birthdate".into()),
            Date(parse_rfc3339_weak("1981-05-16 11:32:06").unwrap().into()),
            String("BiggestNumber".into()),
            Integer(18446744073709551615u64.into()),
            String("SmallestNumber".into()),
            Integer((-9223372036854775808i64).into()),
            String("Lines".into()),
            StartArray(Some(2)),
            String("It is a tale told by an idiot,".into()),
            String("Full of sound and fury, signifying nothing.".into()),
            EndArray,
            String("Death".into()),
            Integer(1564.into()),
            String("Blank".into()),
            String("".into()),
            EndDictionary,
        ];

        assert_eq!(events, comparison);
    }

    #[test]
    fn utf16_plist() {
        let reader = File::open(&Path::new("./tests/data/utf16_bplist.plist")).unwrap();
        let streaming_parser = BinaryReader::new(reader);
        let mut events: Vec<Event> = streaming_parser.map(|e| e.unwrap()).collect();

        assert_eq!(events[2], String("\u{2605} or better".to_owned()));

        let poem = if let String(ref mut poem) = events[4] {
            poem
        } else {
            panic!("not a string")
        };
        assert_eq!(poem.len(), 643);
        assert_eq!(poem.pop().unwrap(), '\u{2605}');
    }
}
<commit_msg>Use explicit error conversion in `BinaryReader`.<commit_after>use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Read, Seek, SeekFrom};
use std::mem::size_of;

use stream::Event;
use {u64_to_usize, Date, Error};

struct StackItem {
    object_ref: u64,
    child_object_refs: Vec<u64>,
    ty: StackType,
}

enum StackType {
    Array,
    Dict,
}

// https://opensource.apple.com/source/CF/CF-550/CFBinaryPList.c
// https://hg.python.org/cpython/file/3.4/Lib/plistlib.py
pub struct BinaryReader<R> {
    stack: Vec<StackItem>,
    object_offsets: Vec<u64>,
    object_on_stack: Vec<bool>,
    reader: R,
    ref_size: u8,
    root_object: u64,
    // The largest single allocation allowed for this plist.
    // Equal to the number of bytes in the plist minus the magic number and trailer.
    max_allocation_bytes: usize,
}

impl<R: Read + Seek> BinaryReader<R> {
    pub fn new(reader: R) -> BinaryReader<R> {
        BinaryReader {
            stack: Vec::new(),
            object_offsets: Vec::new(),
            object_on_stack: Vec::new(),
            reader,
            ref_size: 0,
            root_object: 0,
            max_allocation_bytes: 0,
        }
    }

    fn can_allocate(&self, len: u64, size: usize) -> bool {
        let byte_len = len.saturating_mul(size as u64);
        byte_len <= self.max_allocation_bytes as u64
    }

    fn allocate_vec<T>(&self, len: u64, size: usize) -> Result<Vec<T>, Error> {
        if self.can_allocate(len, size) {
            Ok(Vec::with_capacity(len as usize))
        } else {
            Err(Error::InvalidData)
        }
    }

    fn read_trailer(&mut self) -> Result<(), Error> {
        self.reader.seek(SeekFrom::Start(0))?;
        let mut magic = [0; 8];
        self.reader.read_exact(&mut magic)?;
        if &magic != b"bplist00" {
            return Err(Error::InvalidData);
        }

        // Trailer starts with 6 bytes of padding
        let trailer_start = self.reader.seek(SeekFrom::End(-32 + 6))?;

        let offset_size = self.reader.read_u8()?;
        match offset_size {
            1 | 2 | 4 | 8 => (),
            _ => return Err(Error::InvalidData),
        }

        self.ref_size = self.reader.read_u8()?;
        match self.ref_size {
            1 | 2 | 4 | 8 => (),
            _ => return Err(Error::InvalidData),
        }

        let num_objects = self.reader.read_u64::<BigEndian>()?;
        self.root_object = self.reader.read_u64::<BigEndian>()?;
        let offset_table_offset = self.reader.read_u64::<BigEndian>()?;

        // File size minus trailer and header
        // Truncated to max(usize)
        self.max_allocation_bytes = trailer_start.saturating_sub(8) as usize;

        // Read offset table
        self.reader.seek(SeekFrom::Start(offset_table_offset))?;
        self.object_offsets = self.read_ints(num_objects, offset_size)?;
        self.object_on_stack = vec![false; self.object_offsets.len()];

        Ok(())
    }

    fn read_ints(&mut self, len: u64, size: u8) -> Result<Vec<u64>, Error> {
        let mut ints = self.allocate_vec(len, size as usize)?;
        for _ in 0..len {
            match size {
                1 => ints.push(self.reader.read_u8()?.into()),
                2 => ints.push(self.reader.read_u16::<BigEndian>()?.into()),
                4 => ints.push(self.reader.read_u32::<BigEndian>()?.into()),
                8 => ints.push(self.reader.read_u64::<BigEndian>()?),
                _ => return Err(Error::InvalidData),
            }
        }
        Ok(ints)
    }

    fn read_refs(&mut self, len: u64) -> Result<Vec<u64>, Error> {
        let ref_size = self.ref_size;
        self.read_ints(len, ref_size)
    }

    fn read_object_len(&mut self, len: u8) -> Result<u64, Error> {
        if (len & 0x0f) == 0x0f {
            let len_power_of_two = self.reader.read_u8()? & 0x03;
            Ok(match len_power_of_two {
                0 => self.reader.read_u8()?.into(),
                1 => self.reader.read_u16::<BigEndian>()?.into(),
                2 => self.reader.read_u32::<BigEndian>()?.into(),
                3 => self.reader.read_u64::<BigEndian>()?,
                _ => return Err(Error::InvalidData),
            })
        } else {
            Ok(len.into())
        }
    }

    fn read_data(&mut self, len: u64) -> Result<Vec<u8>, Error> {
        let mut data = self.allocate_vec(len, size_of::<u8>())?;
        data.resize(len as usize, 0);
        self.reader.read_exact(&mut data)?;
        Ok(data)
    }

    fn seek_to_object(&mut self, object_ref: u64) -> Result<u64, Error> {
        let object_ref = u64_to_usize(object_ref).ok_or(Error::InvalidData)?;
        let offset = *self
            .object_offsets
            .get(object_ref)
            .ok_or(Error::InvalidData)?;
        Ok(self.reader.seek(SeekFrom::Start(offset))?)
    }

    fn push_stack_item_and_check_for_recursion(&mut self, item: StackItem) -> Result<(), Error> {
        let object_ref = u64_to_usize(item.object_ref).expect("internal consistency error");
        let is_on_stack = &mut self.object_on_stack[object_ref];
        if *is_on_stack {
            return Err(Error::InvalidData);
        }
        *is_on_stack = true;
        self.stack.push(item);
        Ok(())
    }

    fn pop_stack_item(&mut self) -> StackItem {
        let item = self.stack.pop().expect("internal consistency error");
        let object_ref = u64_to_usize(item.object_ref).expect("internal consistency error");
        self.object_on_stack[object_ref] = false;
        item
    }

    fn read_next(&mut self) -> Result<Option<Event>, Error> {
        let object_ref = if self.ref_size == 0 {
            // Initialise here rather than in new
            self.read_trailer()?;
            self.root_object
        } else {
            let maybe_object_ref = if let Some(stack_item) = self.stack.last_mut() {
                stack_item.child_object_refs.pop()
            } else {
                // Finished reading the plist
                return Ok(None);
            };

            if let Some(object_ref) = maybe_object_ref {
                object_ref
            } else {
                // We're at the end of an array or dict. Pop the top stack item and return.
                let stack_item = self.pop_stack_item();
                match stack_item.ty {
                    StackType::Array => return Ok(Some(Event::EndArray)),
                    StackType::Dict => return Ok(Some(Event::EndDictionary)),
                }
            }
        };

        self.seek_to_object(object_ref)?;

        let token = self.reader.read_u8()?;
        let ty = (token & 0xf0) >> 4;
        let size = token & 0x0f;

        let result = match (ty, size) {
            (0x0, 0x00) => return Err(Error::InvalidData), // null
            (0x0, 0x08) => Some(Event::Boolean(false)),
            (0x0, 0x09) => Some(Event::Boolean(true)),
            (0x0, 0x0f) => return Err(Error::InvalidData), // fill
            (0x1, 0) => Some(Event::Integer(self.reader.read_u8()?.into())),
            (0x1, 1) => Some(Event::Integer(self.reader.read_u16::<BigEndian>()?.into())),
            (0x1, 2) => Some(Event::Integer(self.reader.read_u32::<BigEndian>()?.into())),
            (0x1, 3) => Some(Event::Integer(self.reader.read_i64::<BigEndian>()?.into())),
            (0x1, 4) => {
                let value = self.reader.read_i128::<BigEndian>()?;
                if value < 0 || value > u64::max_value().into() {
                    return Err(Error::InvalidData);
                }
                Some(Event::Integer((value as u64).into()))
            }
            (0x1, _) => return Err(Error::InvalidData), // variable length int
            (0x2, 2) => Some(Event::Real(self.reader.read_f32::<BigEndian>()?.into())),
            (0x2, 3) => Some(Event::Real(self.reader.read_f64::<BigEndian>()?)),
            (0x2, _) => return Err(Error::InvalidData), // odd length float
            (0x3, 3) => {
                // Date. Seconds since 1/1/2001 00:00:00.
                let secs = self.reader.read_f64::<BigEndian>()?;
                Some(Event::Date(
                    Date::from_seconds_since_plist_epoch(secs).map_err(|()| Error::InvalidData)?,
                ))
            }
            (0x4, n) => {
                // Data
                let len = self.read_object_len(n)?;
                Some(Event::Data(self.read_data(len)?))
            }
            (0x5, n) => {
                // ASCII string
                let len = self.read_object_len(n)?;
                let raw = self.read_data(len)?;
                let string = String::from_utf8(raw).map_err(|_| Error::InvalidData)?;
                Some(Event::String(string))
            }
            (0x6, n) => {
                // UTF-16 string
                let len_utf16_codepoints = self.read_object_len(n)?;
                let mut raw_utf16 = self.allocate_vec(len_utf16_codepoints, size_of::<u16>())?;

                for _ in 0..len_utf16_codepoints {
                    raw_utf16.push(self.reader.read_u16::<BigEndian>()?);
                }

                let string = String::from_utf16(&raw_utf16).map_err(|_| Error::InvalidData)?;
                Some(Event::String(string))
            }
            (0xa, n) => {
                // Array
                let len = self.read_object_len(n)?;
                let mut child_object_refs = self.read_refs(len)?;
                // Reverse so we can pop off the end of the stack in order
                child_object_refs.reverse();

                self.push_stack_item_and_check_for_recursion(StackItem {
                    object_ref,
                    ty: StackType::Array,
                    child_object_refs,
                })?;

                Some(Event::StartArray(Some(len)))
            }
            (0xd, n) => {
                // Dict
                let len = self.read_object_len(n)?;
                let key_refs = self.read_refs(len)?;
                let value_refs = self.read_refs(len)?;

                let mut child_object_refs = self.allocate_vec(len * 2, self.ref_size as usize)?;
                let len = key_refs.len();
                for i in 1..len + 1 {
                    // Reverse so we can pop off the end of the stack in order
                    child_object_refs.push(value_refs[len - i]);
                    child_object_refs.push(key_refs[len - i]);
                }

                self.push_stack_item_and_check_for_recursion(StackItem {
                    object_ref,
                    ty: StackType::Dict,
                    child_object_refs,
                })?;

                Some(Event::StartDictionary(Some(len as u64)))
            }
            (_, _) => return Err(Error::InvalidData),
        };

        Ok(result)
    }
}

impl<R: Read + Seek> Iterator for BinaryReader<R> {
    type Item = Result<Event, Error>;

    fn next(&mut self) -> Option<Result<Event, Error>> {
        match self.read_next() {
            Ok(Some(event)) => Some(Ok(event)),
            Err(err) => {
                // Mark the plist as finished
                self.stack.clear();
                Some(Err(err))
            }
            Ok(None) => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use humantime::parse_rfc3339_weak;
    use std::fs::File;
    use std::path::Path;

    use super::*;
    use stream::Event;
    use stream::Event::*;

    #[test]
    fn streaming_parser() {
        let reader = File::open(&Path::new("./tests/data/binary.plist")).unwrap();
        let streaming_parser = BinaryReader::new(reader);
        let events: Vec<Event> = streaming_parser.map(|e| e.unwrap()).collect();

        let comparison = &[
            StartDictionary(Some(9)),
            String("Author".into()),
            String("William Shakespeare".into()),
            String("Height".into()),
            Real(1.6),
            String("Data".into()),
            Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]),
            String("Birthdate".into()),
            Date(parse_rfc3339_weak("1981-05-16 11:32:06").unwrap().into()),
            String("BiggestNumber".into()),
            Integer(18446744073709551615u64.into()),
            String("SmallestNumber".into()),
            Integer((-9223372036854775808i64).into()),
            String("Lines".into()),
            StartArray(Some(2)),
            String("It is a tale told by an idiot,".into()),
            String("Full of sound and fury, signifying nothing.".into()),
            EndArray,
            String("Death".into()),
            Integer(1564.into()),
            String("Blank".into()),
            String("".into()),
            EndDictionary,
        ];

        assert_eq!(events, comparison);
    }

    #[test]
    fn utf16_plist() {
        let reader = File::open(&Path::new("./tests/data/utf16_bplist.plist")).unwrap();
        let streaming_parser = BinaryReader::new(reader);
        let mut events: Vec<Event> = streaming_parser.map(|e| e.unwrap()).collect();

        assert_eq!(events[2], String("\u{2605} or better".to_owned()));

        let poem = if let String(ref mut poem) = events[4] {
            poem
        } else {
            panic!("not a string")
        };
        assert_eq!(poem.len(), 643);
        assert_eq!(poem.pop().unwrap(), '\u{2605}');
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate derive_builder;

#[derive(Debug, Clone, Builder, PartialEq, Eq)]
#[builder(build_fn(validator="LoremBuilder::validate"))]
pub struct Lorem {
    /// A percentile. Must be between 0 and 100.
    my_effort: u8,

    /// A percentile. Must be less than or equal to `Lorem::my_effort`.
    #[builder(default="40")]
    their_effort: u8,

    /// A percentile. Must be between 0 and 100.
    rivals_effort: u8,
}

impl LoremBuilder {
    /// Performs bound checks.
    fn validate(&self) -> Result<(), String> {
        if let Some(ref my_effort) = self.my_effort {
            if *my_effort > 100 {
                return Err("Don't wear yourself out".to_string());
            }
        }

        if let Some(ref their_effort) = self.their_effort {
            if *their_effort > 100 {
                return Err("The game has changed".to_string());
            }
        }

        if let Some(ref rivals_effort) = self.rivals_effort {
            if *rivals_effort > 100 {
                return Err("Your rival is cheating".to_string());
            }
        }

        Ok(())
    }
}

#[test]
fn incomplete_fields() {
    let err_msg = LoremBuilder::default().build().expect_err("Default has uninitialized fields");

    // In this case, the validator should have run but passed because there was no value set for `my_effort`.
    // Adding private `get` methods which return `Result<T, String>` by pulling in defaults will enable the
    // validation function to be improved here.
    assert!(&err_msg != "Don't wear yourself out");
}

#[test]
fn out_of_bounds() {
    assert_eq!("Don't wear yourself out", &LoremBuilder::default().my_effort(120).build().unwrap_err());
    assert_eq!("Your rival is cheating", &LoremBuilder::default().rivals_effort(120).build().unwrap_err());
}

#[test]
fn validation_pass() {
    let lorem = LoremBuilder::default()
        .my_effort(90)
        .rivals_effort(89)
        .build()
        .expect("All validations should be passing");

    assert_eq!(lorem, Lorem {
        my_effort: 90,
        rivals_effort: 89,
        their_effort: 40,
    });
}<commit_msg>Removed expect_err to build on stable<commit_after>#[macro_use]
extern crate derive_builder;

#[derive(Debug, Clone, Builder, PartialEq, Eq)]
#[builder(build_fn(validator="LoremBuilder::validate"))]
pub struct Lorem {
    /// A percentile. Must be between 0 and 100.
    my_effort: u8,

    /// A percentile. Must be less than or equal to `Lorem::my_effort`.
    #[builder(default="40")]
    their_effort: u8,

    /// A percentile. Must be between 0 and 100.
    rivals_effort: u8,
}

impl LoremBuilder {
    /// Performs bound checks.
    fn validate(&self) -> Result<(), String> {
        if let Some(ref my_effort) = self.my_effort {
            if *my_effort > 100 {
                return Err("Don't wear yourself out".to_string());
            }
        }

        if let Some(ref their_effort) = self.their_effort {
            if *their_effort > 100 {
                return Err("The game has changed".to_string());
            }
        }

        if let Some(ref rivals_effort) = self.rivals_effort {
            if *rivals_effort > 100 {
                return Err("Your rival is cheating".to_string());
            }
        }

        Ok(())
    }
}

#[test]
fn incomplete_fields() {
    let err_msg = LoremBuilder::default().build().unwrap_err();

    // In this case, the validator should have run but passed because there was no value set for `my_effort`.
    // Adding private `get` methods which return `Result<T, String>` by pulling in defaults will enable the
    // validation function to be improved here.
    assert!(&err_msg != "Don't wear yourself out");
}

#[test]
fn out_of_bounds() {
    assert_eq!("Don't wear yourself out", &LoremBuilder::default().my_effort(120).build().unwrap_err());
    assert_eq!("Your rival is cheating", &LoremBuilder::default().rivals_effort(120).build().unwrap_err());
}

#[test]
fn validation_pass() {
    let lorem = LoremBuilder::default()
        .my_effort(90)
        .rivals_effort(89)
        .build()
        .expect("All validations should be passing");

    assert_eq!(lorem, Lorem {
        my_effort: 90,
        rivals_effort: 89,
        their_effort: 40,
    });
}<|endoftext|>


<commit_before>use grains;

#[test]
fn square_one() {
    assert_eq!(grains::square(1), 1);
}

#[test]
#[ignore]
fn square_two() {
    assert_eq!(grains::square(2), 2);
}

#[test]
#[ignore]
fn square_three() {
    assert_eq!(grains::square(3), 4);
}

#[test]
#[ignore]
fn square_four() {
    assert_eq!(grains::square(4), 8);
}

#[test]
#[ignore]
fn square_sixteen() {
    assert_eq!(grains::square(16), 32_768);
}

#[test]
#[ignore]
fn square_thirty_two() {
    assert_eq!(grains::square(32), 2_147_483_648);
}

#[test]
#[ignore]
fn square_sixty_four() {
    assert_eq!(grains::square(64), 9_223_372_036_854_775_808);
}

#[test]
#[ignore]
#[should_panic(expected = "Square must be between 1 and 64")]
fn square_zero_panics() {
    grains::square(0);
}

#[test]
#[ignore]
#[should_panic(expected = "Square must be between 1 and 64")]
fn square_sixty_five_panics() {
    grains::square(65);
}

#[test]
#[ignore]
fn total_sums_all_squares() {
    assert_eq!(grains::total(), 18_446_744_073_709_551_615);
}
<commit_msg>grains: Renamed the test suite functions<commit_after>use grains;

fn process_square_case(input: u32, expected: u64) {
    assert_eq!(grains::square(input), expected);
}

#[test]
/// 1
fn test_1() {
    process_square_case(1, 1);
}

#[test]
#[ignore]
/// 2
fn test_2() {
    process_square_case(2, 2);
}

#[test]
#[ignore]
/// 3
fn test_3() {
    process_square_case(3, 4);
}

#[test]
#[ignore]
/// 4
fn test_4() {
    process_square_case(4, 8);
}

//NEW
#[test]
#[ignore]
/// 16
fn test_16() {
    process_square_case(16, 32_768);
}

#[test]
#[ignore]
/// 32
fn test_32() {
    process_square_case(32, 2_147_483_648);
}

#[test]
#[ignore]
/// 64
fn test_64() {
    process_square_case(64, 9_223_372_036_854_775_808);
}

#[test]
#[ignore]
#[should_panic(expected = "Square must be between 1 and 64")]
fn test_square_0_raises_an_exception() {
    grains::square(0);
}

#[test]
#[ignore]
#[should_panic(expected = "Square must be between 1 and 64")]
fn test_square_greater_than_64_raises_an_exception() {
    grains::square(65);
}

#[test]
#[ignore]
fn test_returns_the_total_number_of_grains_on_the_board() {
    assert_eq!(grains::total(), 18_446_744_073_709_551_615);
}
<|endoftext|>


<commit_before>use std::{collections::HashMap, net::SocketAddr};
use std::thread;
use std::time::{Duration, Instant};

use anyhow::Result;
use glam::vec2;
use laminar::Socket;
use legion::*;
use log::{info, LevelFilter};
use rand::prelude::*;
use simplelog::{Config, TermLogger, TerminalMode};

use zombenum_shared::components::{Component, GameEntityId};
use zombenum_shared::entities::make_player;
use zombenum_shared::TICK_DURATION_BUDGET;

mod network;
mod systems;

#[allow(dead_code)]
mod serialize;

use network::receive::get_user_events;
use network::send::{send_server_updates, ScheduledUpdates};

const SERVER: &str = "0.0.0.0:14191";
fn main() -> Result<()> {
    TermLogger::init(LevelFilter::Info, Config::default(), TerminalMode::Mixed)?;

    let mut world = World::default();
    let mut resources = Resources::default();
    let mut schedule = Schedule::builder()
        .add_system(systems::movement_system())
        .build();

    info!("Starting server");

    let mut socket = Socket::bind(SERVER)?;
    let (sender, receiver) = (socket.get_packet_sender(), socket.get_event_receiver());
    let _thread = thread::spawn(move || socket.start_polling());

    // A list of all connected users with their respective game entity id.
    let mut connected_users: HashMap<SocketAddr, GameEntityId> = HashMap::new();

    let session_start_time = Instant::now();
    resources.insert(Duration::default());

    loop {
        let tick_time_at_start = Instant::now();
        // Get all received events, sort them by event and return them in a unified struct.
        let events = get_user_events(&receiver, &mut connected_users)?;

        let mut scheduled_updates = ScheduledUpdates::new();

        // Player joins the game
        for player_id in events.join_game {
            info!("Player {:?} just joined", player_id);
            let mut rng = thread_rng();
            let player = make_player(
                vec2(rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0)),
                player_id,
            );

            world.push(player.clone());

            let mut components = Vec::new();
            components.push(Component::GameEntityId(player.0));
            components.push(Component::Position(player.1));
            components.push(Component::Player(player.2));
            components.push(Component::Drawable(player.3));
            scheduled_updates
                .added_entities
                .insert(GameEntityId::all_users(), components);
        }

        resources.insert(scheduled_updates);

        // Run systems here.
        schedule.execute(&mut world, &mut resources);

        let scheduled_updates = resources
            .get::<ScheduledUpdates>()
            .expect("We put it there.");

        send_server_updates(&sender, &session_start_time, &scheduled_updates)?;

        // We aim to keep every tick the same consistent length.
        // In order to achieve that, we'll sleep only as long as we still have time budget left over
        // after every loop.
        let tick_time_at_end = Instant::now();
        let tick_duration = tick_time_at_end - tick_time_at_start;
        let time_to_sleep = TICK_DURATION_BUDGET.checked_sub(tick_duration).unwrap_or_default();
        thread::sleep(time_to_sleep);

        // The time after sleeping is our "real" final and last time this tick and as such we'll
        // use it in the calculation of this tick's final end time.
        let tick_time_after_sleep = Instant::now();
        let mut last_tick_time = resources.get_mut::<Duration>().expect("Last tick duration should be here");
        *last_tick_time = tick_time_after_sleep - tick_time_at_start;
    }
}
<commit_msg>Add session duration for network messages<commit_after>use std::{collections::HashMap, net::SocketAddr};
use std::thread;
use std::time::{Duration, Instant};

use anyhow::Result;
use glam::vec2;
use laminar::Socket;
use legion::*;
use log::{info, LevelFilter};
use rand::prelude::*;
use simplelog::{Config, TermLogger, TerminalMode};

use zombenum_shared::components::{Component, GameEntityId};
use zombenum_shared::entities::make_player;
use zombenum_shared::TICK_DURATION_BUDGET;

mod network;
mod systems;

#[allow(dead_code)]
mod serialize;

use network::receive::get_user_events;
use network::send::{send_server_updates, ScheduledUpdates};

const SERVER: &str = "0.0.0.0:14191";
fn main() -> Result<()> {
    TermLogger::init(LevelFilter::Info, Config::default(), TerminalMode::Mixed)?;

    let mut world = World::default();
    let mut resources = Resources::default();
    let mut schedule = Schedule::builder()
        .add_system(systems::movement_system())
        .build();

    info!("Starting server");

    let mut socket = Socket::bind(SERVER)?;
    let (sender, receiver) = (socket.get_packet_sender(), socket.get_event_receiver());
    let _thread = thread::spawn(move || socket.start_polling());

    // A list of all connected users with their respective game entity id.
    let mut connected_users: HashMap<SocketAddr, GameEntityId> = HashMap::new();

    // Used for recording how long this current server session has been open which in turn is then
    // used for calculating the session timestamp for use in network messages.
    let session_start_time = Instant::now();
    resources.insert(Duration::default());

    loop {
        let tick_time_at_start = Instant::now();
        // Get all received events, sort them by event and return them in a unified struct.
        let events = get_user_events(&receiver, &mut connected_users)?;

        let mut scheduled_updates = ScheduledUpdates::new();

        // Player joins the game
        for player_id in events.join_game {
            info!("Player {:?} just joined", player_id);
            let mut rng = thread_rng();
            let player = make_player(
                vec2(rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0)),
                player_id,
            );

            world.push(player.clone());

            let mut components = Vec::new();
            components.push(Component::GameEntityId(player.0));
            components.push(Component::Position(player.1));
            components.push(Component::Player(player.2));
            components.push(Component::Drawable(player.3));
            scheduled_updates
                .added_entities
                .insert(GameEntityId::all_users(), components);
        }

        resources.insert(scheduled_updates);

        // Run systems here.
        schedule.execute(&mut world, &mut resources);

        let scheduled_updates = resources
            .get::<ScheduledUpdates>()
            .expect("We put it there.");

        // The session duration is used as a snapshot timestamp in server-sent network messages.
        let session_duration = session_start_time - Instant::now();
        send_server_updates(&sender, session_duration, &scheduled_updates)?;

        // We aim to keep every tick the same consistent length.
        // In order to achieve that, we'll sleep only as long as we still have time budget left over
        // after every loop.
        let tick_time_at_end = Instant::now();
        let tick_duration = tick_time_at_end - tick_time_at_start;
        let time_to_sleep = TICK_DURATION_BUDGET.checked_sub(tick_duration).unwrap_or_default();
        thread::sleep(time_to_sleep);

        // The time after sleeping is our "real" final and last time this tick and as such we'll
        // use it in the calculation of this tick's final end time.
        let tick_time_after_sleep = Instant::now();
        let mut last_tick_time = resources.get_mut::<Duration>().expect("Last tick duration should be here");
        *last_tick_time = tick_time_after_sleep - tick_time_at_start;
    }
}
<|endoftext|>