<commit_before>//! FIXME: write short doc here

mod help;

use core::fmt::Write;
use core::str;
use pico_args::Arguments;
use std::{env, path::PathBuf};
use xtask::{
    codegen::{self, Mode},
    install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt, run_with_output, Cmd, Result,
};

// Latest stable, feel free to send a PR if this lags behind.
const REQUIRED_RUST_VERSION: u32 = 38;

struct InstallOpt {
    client: Option<ClientOpt>,
    server: Option<ServerOpt>,
}

enum ClientOpt {
    VsCode,
}

struct ServerOpt {
    jemalloc: bool,
}

fn main() -> Result<()> {
    let subcommand = match std::env::args_os().nth(1) {
        None => {
            eprintln!("{}", help::GLOBAL_HELP);
            return Ok(());
        }
        Some(s) => s,
    };
    let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());
    let subcommand = &*subcommand.to_string_lossy();
    match subcommand {
        "install" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::INSTALL_HELP);
                return Ok(());
            }
            let server = matches.contains("--server");
            let client_code = matches.contains("--client-code");
            if server && client_code {
                eprintln!("{}", help::INSTALL_RA_CONFLICT);
                return Ok(());
            }
            let jemalloc = matches.contains("--jemalloc");
            matches.finish().or_else(handle_extra_flags)?;
            let opts = InstallOpt {
                client: if server { None } else { Some(ClientOpt::VsCode) },
                server: if client_code { None } else { Some(ServerOpt { jemalloc: jemalloc }) },
            };
            install(opts)?
        }
        "codegen" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            codegen::generate_syntax(Mode::Overwrite)?;
            codegen::generate_parser_tests(Mode::Overwrite)?;
            codegen::generate_assists_docs(Mode::Overwrite)?;
        }
        "format" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_rustfmt(Mode::Overwrite)?
        }
        "format-hook" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            install_format_hook()?
        }
        "lint" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_clippy()?
        }
        "fuzz-tests" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_fuzzer()?
        }
        _ => eprintln!("{}", help::GLOBAL_HELP),
    }
    Ok(())
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        Err(format!("Invalid flags: {}", invalid_flags).into())
    } else {
        Err(e.to_string().into())
    }
}

fn install(opts: InstallOpt) -> Result<()> {
    if cfg!(target_os = "macos") {
        fix_path_for_mac()?
    }
    if let Some(server) = opts.server {
        install_server(server)?;
    }
    if let Some(client) = opts.client {
        install_client(client)?;
    }
    Ok(())
}

fn fix_path_for_mac() -> Result<()> {
    let mut vscode_path: Vec<PathBuf> = {
        const COMMON_APP_PATH: &str =
            r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
        const ROOT_DIR: &str = "";
        let home_dir = match env::var("HOME") {
            Ok(home) => home,
            Err(e) => Err(format!("Failed getting HOME from environment with error: {}.", e))?,
        };

        [ROOT_DIR, &home_dir]
            .iter()
            .map(|dir| String::from(*dir) + COMMON_APP_PATH)
            .map(PathBuf::from)
            .filter(|path| path.exists())
            .collect()
    };

    if !vscode_path.is_empty() {
        let vars = match env::var_os("PATH") {
            Some(path) => path,
            None => Err("Could not get PATH variable from env.")?,
        };

        let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
        paths.append(&mut vscode_path);
        let new_paths = env::join_paths(paths)?;
        env::set_var("PATH", &new_paths);
    }

    Ok(())
}

fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
    Cmd { unix: r"npm ci", windows: r"cmd.exe /c npm.cmd ci", work_dir: "./editors/code" }.run()?;
    Cmd {
        unix: r"npm run package",
        windows: r"cmd.exe /c npm.cmd run package",
        work_dir: "./editors/code",
    }
    .run()?;

    let code_binary = ["code", "code-insiders", "codium"].iter().find(|bin| {
        Cmd {
            unix: &format!("{} --version", bin),
            windows: &format!("cmd.exe /c {}.cmd --version", bin),
            work_dir: "./editors/code",
        }
        .run()
        .is_ok()
    });

    let code_binary = match code_binary {
        Some(it) => it,
        None => Err("Can't execute `code --version`. Perhaps it is not in $PATH?")?,
    };

    Cmd {
        unix: &format!(r"{} --install-extension ./ra-lsp-0.0.1.vsix --force", code_binary),
        windows: &format!(
            r"cmd.exe /c {}.cmd --install-extension ./ra-lsp-0.0.1.vsix --force",
            code_binary
        ),
        work_dir: "./editors/code",
    }
    .run()?;

    let output = Cmd {
        unix: &format!(r"{} --list-extensions", code_binary),
        windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary),
        work_dir: ".",
    }
    .run_with_output()?;

    if !str::from_utf8(&output.stdout)?.contains("ra-lsp") {
        Err("Could not install the Visual Studio Code extension. \
             Please make sure you have at least NodeJS 10.x installed and try again.")?;
    }

    Ok(())
}

fn install_server(opts: ServerOpt) -> Result<()> {
    let mut old_rust = false;
    if let Ok(output) = run_with_output("cargo --version", ".") {
        if let Ok(stdout) = String::from_utf8(output.stdout) {
            if !check_version(&stdout, REQUIRED_RUST_VERSION) {
                old_rust = true;
            }
        }
    }

    if old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION
        )
    }

    let res = if opts.jemalloc {
        run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".")
    } else {
        run("cargo install --path crates/ra_lsp_server --locked --force", ".")
    };

    if res.is_err() && old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION
        )
    }

    res
}

fn check_version(version_output: &str, min_minor_version: u32) -> bool {
    // Parse second the number out of
    //      cargo 1.39.0-beta (1c6ec66d5 2019-09-30)
    let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok());
    match minor {
        None => true,
        Some(minor) => minor >= min_minor_version,
    }
}
<commit_msg>warn if npm is not found<commit_after>//! FIXME: write short doc here

mod help;

use core::fmt::Write;
use core::str;
use pico_args::Arguments;
use std::{env, path::PathBuf};
use xtask::{
    codegen::{self, Mode},
    install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt, run_with_output, Cmd, Result,
};

// Latest stable, feel free to send a PR if this lags behind.
const REQUIRED_RUST_VERSION: u32 = 38;

struct InstallOpt {
    client: Option<ClientOpt>,
    server: Option<ServerOpt>,
}

enum ClientOpt {
    VsCode,
}

struct ServerOpt {
    jemalloc: bool,
}

fn main() -> Result<()> {
    let subcommand = match std::env::args_os().nth(1) {
        None => {
            eprintln!("{}", help::GLOBAL_HELP);
            return Ok(());
        }
        Some(s) => s,
    };
    let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());
    let subcommand = &*subcommand.to_string_lossy();
    match subcommand {
        "install" => {
            if matches.contains(["-h", "--help"]) {
                eprintln!("{}", help::INSTALL_HELP);
                return Ok(());
            }
            let server = matches.contains("--server");
            let client_code = matches.contains("--client-code");
            if server && client_code {
                eprintln!("{}", help::INSTALL_RA_CONFLICT);
                return Ok(());
            }
            let jemalloc = matches.contains("--jemalloc");
            matches.finish().or_else(handle_extra_flags)?;
            let opts = InstallOpt {
                client: if server { None } else { Some(ClientOpt::VsCode) },
                server: if client_code { None } else { Some(ServerOpt { jemalloc: jemalloc }) },
            };
            install(opts)?
        }
        "codegen" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            codegen::generate_syntax(Mode::Overwrite)?;
            codegen::generate_parser_tests(Mode::Overwrite)?;
            codegen::generate_assists_docs(Mode::Overwrite)?;
        }
        "format" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_rustfmt(Mode::Overwrite)?
        }
        "format-hook" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            install_format_hook()?
        }
        "lint" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_clippy()?
        }
        "fuzz-tests" => {
            if matches.contains(["-h", "--help"]) {
                help::print_no_param_subcommand_help(&subcommand);
                return Ok(());
            }
            run_fuzzer()?
        }
        _ => eprintln!("{}", help::GLOBAL_HELP),
    }
    Ok(())
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        Err(format!("Invalid flags: {}", invalid_flags).into())
    } else {
        Err(e.to_string().into())
    }
}

fn install(opts: InstallOpt) -> Result<()> {
    if cfg!(target_os = "macos") {
        fix_path_for_mac()?
    }
    if let Some(server) = opts.server {
        install_server(server)?;
    }
    if let Some(client) = opts.client {
        install_client(client)?;
    }
    Ok(())
}

fn fix_path_for_mac() -> Result<()> {
    let mut vscode_path: Vec<PathBuf> = {
        const COMMON_APP_PATH: &str =
            r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
        const ROOT_DIR: &str = "";
        let home_dir = match env::var("HOME") {
            Ok(home) => home,
            Err(e) => Err(format!("Failed getting HOME from environment with error: {}.", e))?,
        };

        [ROOT_DIR, &home_dir]
            .iter()
            .map(|dir| String::from(*dir) + COMMON_APP_PATH)
            .map(PathBuf::from)
            .filter(|path| path.exists())
            .collect()
    };

    if !vscode_path.is_empty() {
        let vars = match env::var_os("PATH") {
            Some(path) => path,
            None => Err("Could not get PATH variable from env.")?,
        };

        let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
        paths.append(&mut vscode_path);
        let new_paths = env::join_paths(paths)?;
        env::set_var("PATH", &new_paths);
    }

    Ok(())
}

fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
    let npm_version = Cmd {
        unix: r"npm --version",
        windows: r"cmd.exe /c npm.cmd --version",
        work_dir: "./editors/code",
    }
    .run();

    if npm_version.is_err() {
        eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin")
    }

    Cmd { unix: r"npm ci", windows: r"cmd.exe /c npm.cmd ci", work_dir: "./editors/code" }.run()?;
    Cmd {
        unix: r"npm run package",
        windows: r"cmd.exe /c npm.cmd run package",
        work_dir: "./editors/code",
    }
    .run()?;

    let code_binary = ["code", "code-insiders", "codium"].iter().find(|bin| {
        Cmd {
            unix: &format!("{} --version", bin),
            windows: &format!("cmd.exe /c {}.cmd --version", bin),
            work_dir: "./editors/code",
        }
        .run()
        .is_ok()
    });

    let code_binary = match code_binary {
        Some(it) => it,
        None => Err("Can't execute `code --version`. Perhaps it is not in $PATH?")?,
    };

    Cmd {
        unix: &format!(r"{} --install-extension ./ra-lsp-0.0.1.vsix --force", code_binary),
        windows: &format!(
            r"cmd.exe /c {}.cmd --install-extension ./ra-lsp-0.0.1.vsix --force",
            code_binary
        ),
        work_dir: "./editors/code",
    }
    .run()?;

    let output = Cmd {
        unix: &format!(r"{} --list-extensions", code_binary),
        windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary),
        work_dir: ".",
    }
    .run_with_output()?;

    if !str::from_utf8(&output.stdout)?.contains("ra-lsp") {
        Err("Could not install the Visual Studio Code extension. \
             Please make sure you have at least NodeJS 10.x installed and try again.")?;
    }

    Ok(())
}

fn install_server(opts: ServerOpt) -> Result<()> {
    let mut old_rust = false;
    if let Ok(output) = run_with_output("cargo --version", ".") {
        if let Ok(stdout) = String::from_utf8(output.stdout) {
            if !check_version(&stdout, REQUIRED_RUST_VERSION) {
                old_rust = true;
            }
        }
    }

    if old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION
        )
    }

    let res = if opts.jemalloc {
        run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".")
    } else {
        run("cargo install --path crates/ra_lsp_server --locked --force", ".")
    };

    if res.is_err() && old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION
        )
    }

    res
}

fn check_version(version_output: &str, min_minor_version: u32) -> bool {
    // Parse second the number out of
    //      cargo 1.39.0-beta (1c6ec66d5 2019-09-30)
    let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok());
    match minor {
        None => true,
        Some(minor) => minor >= min_minor_version,
    }
}
<|endoftext|>


<commit_before>use {IntoBuf, ByteBuf, SliceBuf};

use std::cell::UnsafeCell;
use std::sync::Arc;
use std::{cmp, fmt, ops};

/// A reference counted slice of bytes.
///
/// A `Bytes` is an immutable sequence of bytes. Given that it is guaranteed to
/// be immutable, `Bytes` is `Sync`, `Clone` is shallow (ref count increment),
/// and all operations only update views into the underlying data without
/// requiring any copies.
#[derive(Eq)]
pub struct Bytes {
    inner: BytesMut,
}

/// A unique reference to a slice of bytes.
///
/// A `BytesMut` is a unique handle to a slice of bytes allowing mutation of
/// the underlying bytes.
pub struct BytesMut {
    mem: Mem,
    pos: usize,
    len: usize,
    cap: usize,
}

struct Mem {
    inner: Arc<UnsafeCell<Box<[u8]>>>,
}

/*
 *
 * ===== Bytes =====
 *
 */

impl Bytes {
    /// Creates a new `Bytes` and copy the given slice into it.
    pub fn from_slice<T: AsRef<[u8]>>(bytes: T) -> Bytes {
        BytesMut::from_slice(bytes).freeze()
    }

    /// Returns the number of bytes contained in this `Bytes`.
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    /// Returns true if the value contains no bytes
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    /// Returns the inner contents of this `Bytes` as a slice.
    pub fn as_slice(&self) -> &[u8] {
        self.as_ref()
    }

    /// Extracts a new `Bytes` referencing the bytes from range [start, end).
    pub fn slice(&self, start: usize, end: usize) -> Bytes {
        let mut ret = self.clone();

        ret.inner
            .set_end(end)
            .set_start(start);

        ret
    }

    /// Extracts a new `Bytes` referencing the bytes from range [start, len).
    pub fn slice_from(&self, start: usize) -> Bytes {
        self.slice(start, self.len())
    }

    /// Extracts a new `Bytes` referencing the bytes from range [0, end).
    pub fn slice_to(&self, end: usize) -> Bytes {
        self.slice(0, end)
    }

    /// Splits the bytes into two at the given index.
    ///
    /// Afterwards `self` contains elements `[0, at)`, and the returned `Bytes`
    /// contains elements `[at, len)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > len`
    pub fn split_off(&mut self, at: usize) -> Bytes {
        self.inner.split_off(at).freeze()
    }

    /// Splits the buffer into two at the given index.
    ///
    /// Afterwards `self` contains elements `[at, len)`, and the returned
    /// `Bytes` contains elements `[0, at)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > len`
    pub fn drain_to(&mut self, at: usize) -> Bytes {
        self.inner.drain_to(at).freeze()
    }

    /// Attempt to convert into a `BytesMut` handle.
    ///
    /// This will only succeed if there are no other outstanding references to
    /// the underlying chunk of memory.
    pub fn try_mut(mut self) -> Result<BytesMut, Bytes> {
        if self.inner.mem.is_mut_safe() {
            Ok(self.inner)
        } else {
            Err(self)
        }
    }

    /// Consumes handle, returning a new mutable handle
    ///
    /// The function attempts to avoid copying, however if it is unable to
    /// obtain a unique reference to the underlying data, a new buffer is
    /// allocated and the data is copied to it.
    pub fn into_mut(self) -> BytesMut {
        self.try_mut().unwrap_or_else(BytesMut::from_slice)
    }
}

impl IntoBuf for Bytes {
    type Buf = SliceBuf<Self>;

    fn into_buf(self) -> Self::Buf {
        SliceBuf::new(self)
    }
}

impl<'a> IntoBuf for &'a Bytes {
    type Buf = SliceBuf<Self>;

    fn into_buf(self) -> Self::Buf {
        SliceBuf::new(self)
    }
}

impl Clone for Bytes {
    fn clone(&self) -> Bytes {
        Bytes { inner: self.inner.shallow_clone() }
    }
}

impl AsRef<[u8]> for Bytes {
    fn as_ref(&self) -> &[u8] {
        self.inner.as_ref()
    }
}

impl ops::Deref for Bytes {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl From<BytesMut> for Bytes {
    fn from(src: BytesMut) -> Bytes {
        src.freeze()
    }
}

impl From<Vec<u8>> for Bytes {
    fn from(src: Vec<u8>) -> Bytes {
        BytesMut::from(src).freeze()
    }
}

impl<'a> From<&'a [u8]> for Bytes {
    fn from(src: &'a [u8]) -> Bytes {
        BytesMut::from(src).freeze()
    }
}

impl PartialEq for Bytes {
    fn eq(&self, other: &Bytes) -> bool {
        self.inner == other.inner
    }
}

impl fmt::Debug for Bytes {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.inner, fmt)
    }
}

unsafe impl Sync for Bytes {}

/*
 *
 * ===== BytesMut =====
 *
 */

impl BytesMut {
    /// Create a new `BytesMut` with the specified capacity.
    pub fn with_capacity(cap: usize) -> BytesMut {
        BytesMut {
            mem: Mem::with_capacity(cap),
            pos: 0,
            len: 0,
            cap: cap,
        }
    }

    /// Creates a new `BytesMut` and copy the given slice into it.
    pub fn from_slice<T: AsRef<[u8]>>(bytes: T) -> BytesMut {
        let buf = ByteBuf::from_slice(bytes);
        buf.into_inner()
    }

    /// Returns the number of bytes contained in this `BytesMut`.
    pub fn len(&self) -> usize {
        self.len
    }

    /// Returns true if the value contains no bytes
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the total byte capacity of this `BytesMut`
    pub fn capacity(&self) -> usize {
        self.cap
    }

    /// Return an immutable handle to the bytes
    pub fn freeze(self) -> Bytes {
        Bytes { inner: self }
    }

    /// Splits the bytes into two at the given index.
    ///
    /// Afterwards `self` contains elements `[0, at)`, and the returned
    /// `BytesMut` contains elements `[at, capacity)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > capacity`
    pub fn split_off(&mut self, at: usize) -> BytesMut {
        let mut other = self.shallow_clone();

        other.set_start(at);
        self.set_end(at);

        return other
    }

    /// Splits the buffer into two at the given index.
    ///
    /// Afterwards `self` contains elements `[at, len)`, and the returned `BytesMut`
    /// contains elements `[0, at)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > len`
    pub fn drain_to(&mut self, at: usize) -> BytesMut {
        let mut other = self.shallow_clone();

        other.set_end(at);
        self.set_start(at);

        return other
    }

    /// Returns the inner contents of this `BytesMut` as a slice.
    pub fn as_slice(&self) -> &[u8] {
        self.as_ref()
    }

    /// Returns the inner contents of this `BytesMut` as a mutable slice
    ///
    /// This a slice of bytes that have been initialized
    pub fn as_mut(&mut self) -> &mut [u8] {
        let end = self.pos + self.len;
        &mut self.mem.as_mut()[self.pos..end]
    }

    /// Sets the length of the buffer
    ///
    /// This will explicitly set the size of the buffer without actually
    /// modifying the data, so it is up to the caller to ensure that the data
    /// has been initialized.
    ///
    /// # Panics
    ///
    /// This method will panic if `len` is out of bounds for the underlying
    /// slice or if it comes after the `end` of the configured window.
    pub unsafe fn set_len(&mut self, len: usize) {
        assert!(len <= self.cap);
        self.len = len;
    }

    /// Returns the inner contents of this `BytesMut` as a mutable slice
    ///
    /// This a slice of all bytes, including uninitialized memory
    pub unsafe fn as_raw(&mut self) -> &mut [u8] {
        let end = self.pos + self.cap;
        &mut self.mem.as_mut()[self.pos..end]
    }

    /// Changes the starting index of this window to the index specified.
    ///
    /// Returns the windows back to chain multiple calls to this method.
    ///
    /// # Panics
    ///
    /// This method will panic if `start` is out of bounds for the underlying
    /// slice.
    fn set_start(&mut self, start: usize) -> &mut BytesMut {
        assert!(start <= self.cap);
        self.pos += start;

        if self.len >= start {
            self.len -= start;
        } else {
            self.len = 0;
        }

        self.cap -= start;
        self
    }

    /// Changes the end index of this window to the index specified.
    ///
    /// Returns the windows back to chain multiple calls to this method.
    ///
    /// # Panics
    ///
    /// This method will panic if `start` is out of bounds for the underlying
    /// slice.
    fn set_end(&mut self, end: usize) -> &mut BytesMut {
        assert!(end <= self.cap);
        self.cap = end;
        self.len = cmp::min(self.len, end);
        self
    }

    /// Increments the ref count. This should only be done if it is known that
    /// it can be done safely. As such, this fn is not public, instead other
    /// fns will use this one while maintaining the guarantees.
    fn shallow_clone(&self) -> BytesMut {
         BytesMut {
            mem: self.mem.clone(),
            .. *self
        }
    }
}

impl IntoBuf for BytesMut {
    type Buf = SliceBuf<Self>;

    fn into_buf(self) -> Self::Buf {
        SliceBuf::new(self)
    }
}

impl<'a> IntoBuf for &'a BytesMut {
    type Buf = SliceBuf<&'a BytesMut>;

    fn into_buf(self) -> Self::Buf {
        SliceBuf::new(self)
    }
}

impl AsRef<[u8]> for BytesMut {
    fn as_ref(&self) -> &[u8] {
        let end = self.pos + self.len;
        &self.mem.as_ref()[self.pos..end]
    }
}

impl ops::Deref for BytesMut {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl ops::DerefMut for BytesMut {
    fn deref_mut(&mut self) -> &mut [u8] {
        self.as_mut()
    }
}

impl From<Vec<u8>> for BytesMut {
    fn from(src: Vec<u8>) -> BytesMut {
        let len = src.len();
        let cap = src.capacity();

        BytesMut {
            mem: Mem::from_vec(src),
            pos: 0,
            len: len,
            cap: cap,
        }
    }
}

impl<'a> From<&'a [u8]> for BytesMut {
    fn from(src: &'a [u8]) -> BytesMut {
        BytesMut::from_slice(src)
    }
}

impl PartialEq for BytesMut {
    fn eq(&self, other: &BytesMut) -> bool {
        **self == **other
    }
}

impl Eq for BytesMut {
}

impl fmt::Debug for BytesMut {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_ref(), fmt)
    }
}

unsafe impl Send for BytesMut {}

/*
 *
 * ===== Mem =====
 *
 */

impl Mem {
    fn with_capacity(cap: usize) -> Mem {
        let mut vec = Vec::with_capacity(cap);
        unsafe { vec.set_len(cap); }

        Mem { inner: Arc::new(UnsafeCell::new(vec.into_boxed_slice())) }
    }

    fn from_vec(mut vec: Vec<u8>) -> Mem {
        let cap = vec.capacity();
        unsafe { vec.set_len(cap); }

        Mem { inner: Arc::new(UnsafeCell::new(vec.into_boxed_slice())) }
    }

    fn as_ref(&self) -> &[u8] {
        unsafe { &*self.inner.get() }
    }

    fn as_mut(&mut self) -> &mut [u8] {
        unsafe { &mut *self.inner.get() }
    }

    fn is_mut_safe(&mut self) -> bool {
        Arc::get_mut(&mut self.inner).is_some()
    }

    fn clone(&self) -> Mem {
        Mem { inner: self.inner.clone() }
    }
}

/*
 *
 * ===== PartialEq =====
 *
 */

impl PartialEq<[u8]> for BytesMut {
    fn eq(&self, other: &[u8]) -> bool {
        &**self == other
    }
}

impl PartialEq<BytesMut> for [u8] {
    fn eq(&self, other: &BytesMut) -> bool {
        *other == *self
    }
}

impl PartialEq<Vec<u8>> for BytesMut {
    fn eq(&self, other: &Vec<u8>) -> bool {
        *self == &other[..]
    }
}

impl PartialEq<BytesMut> for Vec<u8> {
    fn eq(&self, other: &BytesMut) -> bool {
        *other == *self
    }
}

impl<'a, T: ?Sized> PartialEq<&'a T> for BytesMut
    where BytesMut: PartialEq<T>
{
    fn eq(&self, other: &&'a T) -> bool {
        *self == **other
    }
}

impl<'a> PartialEq<BytesMut> for &'a [u8] {
    fn eq(&self, other: &BytesMut) -> bool {
        *other == *self
    }
}

impl PartialEq<[u8]> for Bytes {
    fn eq(&self, other: &[u8]) -> bool {
        self.inner == *other
    }
}

impl PartialEq<Bytes> for [u8] {
    fn eq(&self, other: &Bytes) -> bool {
        *other == *self
    }
}

impl PartialEq<Vec<u8>> for Bytes {
    fn eq(&self, other: &Vec<u8>) -> bool {
        *self == &other[..]
    }
}

impl PartialEq<Bytes> for Vec<u8> {
    fn eq(&self, other: &Bytes) -> bool {
        *other == *self
    }
}

impl<'a> PartialEq<Bytes> for &'a [u8] {
    fn eq(&self, other: &Bytes) -> bool {
        *other == *self
    }
}

impl<'a, T: ?Sized> PartialEq<&'a T> for Bytes
    where Bytes: PartialEq<T>
{
    fn eq(&self, other: &&'a T) -> bool {
        *self == **other
    }
}

impl Clone for BytesMut {
    fn clone(&self) -> BytesMut {
        let mut v = Vec::with_capacity(self.len());
        v.extend_from_slice(&self[..]);
        BytesMut {
            mem: Mem { inner : Arc::new(UnsafeCell::new(v.into_boxed_slice())) },
            pos: self.pos,
            len: self.len,
            cap: self.cap,
        }
    }
}
<commit_msg>Lazily allocate the Arc<commit_after>use {IntoBuf, ByteBuf, SliceBuf};

use std::{cmp, fmt, mem, ops, slice};
use std::cell::UnsafeCell;
use std::sync::Arc;

/// A reference counted slice of bytes.
///
/// A `Bytes` is an immutable sequence of bytes. Given that it is guaranteed to
/// be immutable, `Bytes` is `Sync`, `Clone` is shallow (ref count increment),
/// and all operations only update views into the underlying data without
/// requiring any copies.
#[derive(Eq)]
pub struct Bytes {
    inner: BytesMut,
}

/// A unique reference to a slice of bytes.
///
/// A `BytesMut` is a unique handle to a slice of bytes allowing mutation of
/// the underlying bytes.
pub struct BytesMut {
    // Pointer to the start of the memory owned by this BytesMut
    ptr: *mut u8,

    // Number of bytes that have been initialized
    len: usize,

    // Total number of bytes owned by this BytesMut
    cap: usize,

    // If this pointer is set, then the the BytesMut is backed by an Arc
    arc: UnsafeCell<Option<Arc<Vec<u8>>>>,
}

/*
 *
 * ===== Bytes =====
 *
 */

impl Bytes {
    /// Creates a new `Bytes` and copy the given slice into it.
    pub fn from_slice<T: AsRef<[u8]>>(bytes: T) -> Bytes {
        BytesMut::from_slice(bytes).freeze()
    }

    /// Returns the number of bytes contained in this `Bytes`.
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    /// Returns true if the value contains no bytes
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    /// Returns the inner contents of this `Bytes` as a slice.
    pub fn as_slice(&self) -> &[u8] {
        self.as_ref()
    }

    /// Extracts a new `Bytes` referencing the bytes from range [start, end).
    pub fn slice(&self, start: usize, end: usize) -> Bytes {
        let mut ret = self.clone();

        unsafe {
            ret.inner.set_end(end);
            ret.inner.set_start(start);
        }

        ret
    }

    /// Extracts a new `Bytes` referencing the bytes from range [start, len).
    pub fn slice_from(&self, start: usize) -> Bytes {
        self.slice(start, self.len())
    }

    /// Extracts a new `Bytes` referencing the bytes from range [0, end).
    pub fn slice_to(&self, end: usize) -> Bytes {
        self.slice(0, end)
    }

    /// Splits the bytes into two at the given index.
    ///
    /// Afterwards `self` contains elements `[0, at)`, and the returned `Bytes`
    /// contains elements `[at, len)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > len`
    pub fn split_off(&mut self, at: usize) -> Bytes {
        self.inner.split_off(at).freeze()
    }

    /// Splits the buffer into two at the given index.
    ///
    /// Afterwards `self` contains elements `[at, len)`, and the returned
    /// `Bytes` contains elements `[0, at)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > len`
    pub fn drain_to(&mut self, at: usize) -> Bytes {
        self.inner.drain_to(at).freeze()
    }

    /// Attempt to convert into a `BytesMut` handle.
    ///
    /// This will only succeed if there are no other outstanding references to
    /// the underlying chunk of memory.
    pub fn try_mut(mut self) -> Result<BytesMut, Bytes> {
        if self.inner.is_mut_safe() {
            Ok(self.inner)
        } else {
            Err(self)
        }
    }

    /// Consumes handle, returning a new mutable handle
    ///
    /// The function attempts to avoid copying, however if it is unable to
    /// obtain a unique reference to the underlying data, a new buffer is
    /// allocated and the data is copied to it.
    pub fn into_mut(self) -> BytesMut {
        self.try_mut().unwrap_or_else(BytesMut::from_slice)
    }
}

impl IntoBuf for Bytes {
    type Buf = SliceBuf<Self>;

    fn into_buf(self) -> Self::Buf {
        SliceBuf::new(self)
    }
}

impl<'a> IntoBuf for &'a Bytes {
    type Buf = SliceBuf<Self>;

    fn into_buf(self) -> Self::Buf {
        SliceBuf::new(self)
    }
}

impl Clone for Bytes {
    fn clone(&self) -> Bytes {
        Bytes { inner: self.inner.shallow_clone() }
    }
}

impl AsRef<[u8]> for Bytes {
    fn as_ref(&self) -> &[u8] {
        self.inner.as_ref()
    }
}

impl ops::Deref for Bytes {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl From<BytesMut> for Bytes {
    fn from(src: BytesMut) -> Bytes {
        src.freeze()
    }
}

impl From<Vec<u8>> for Bytes {
    fn from(src: Vec<u8>) -> Bytes {
        BytesMut::from(src).freeze()
    }
}

impl<'a> From<&'a [u8]> for Bytes {
    fn from(src: &'a [u8]) -> Bytes {
        BytesMut::from(src).freeze()
    }
}

impl PartialEq for Bytes {
    fn eq(&self, other: &Bytes) -> bool {
        self.inner == other.inner
    }
}

impl fmt::Debug for Bytes {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.inner, fmt)
    }
}

unsafe impl Sync for Bytes {}

/*
 *
 * ===== BytesMut =====
 *
 */

impl BytesMut {
    /// Create a new `BytesMut` with the specified capacity.
    pub fn with_capacity(cap: usize) -> BytesMut {
        BytesMut::from(Vec::with_capacity(cap))
    }

    /// Creates a new `BytesMut` and copy the given slice into it.
    pub fn from_slice<T: AsRef<[u8]>>(bytes: T) -> BytesMut {
        let buf = ByteBuf::from_slice(bytes);
        buf.into_inner()
    }

    /// Returns the number of bytes contained in this `BytesMut`.
    pub fn len(&self) -> usize {
        self.len
    }

    /// Returns true if the value contains no bytes
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the total byte capacity of this `BytesMut`
    pub fn capacity(&self) -> usize {
        self.cap
    }

    /// Return an immutable handle to the bytes
    pub fn freeze(self) -> Bytes {
        Bytes { inner: self }
    }

    /// Splits the bytes into two at the given index.
    ///
    /// Afterwards `self` contains elements `[0, at)`, and the returned
    /// `BytesMut` contains elements `[at, capacity)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > capacity`
    pub fn split_off(&mut self, at: usize) -> BytesMut {
        let mut other = self.shallow_clone();

        unsafe {
            other.set_start(at);
            self.set_end(at);
        }

        return other
    }

    /// Splits the buffer into two at the given index.
    ///
    /// Afterwards `self` contains elements `[at, len)`, and the returned `BytesMut`
    /// contains elements `[0, at)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > len`
    pub fn drain_to(&mut self, at: usize) -> BytesMut {
        let mut other = self.shallow_clone();

        unsafe {
            other.set_end(at);
            self.set_start(at);
        }

        return other
    }

    /// Returns the inner contents of this `BytesMut` as a slice.
    pub fn as_slice(&self) -> &[u8] {
        self.as_ref()
    }

    /// Returns the inner contents of this `BytesMut` as a mutable slice
    ///
    /// This a slice of bytes that have been initialized
    pub fn as_mut(&mut self) -> &mut [u8] {
        unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
    }

    /// Sets the length of the buffer
    ///
    /// This will explicitly set the size of the buffer without actually
    /// modifying the data, so it is up to the caller to ensure that the data
    /// has been initialized.
    ///
    /// # Panics
    ///
    /// This method will panic if `len` is out of bounds for the underlying
    /// slice or if it comes after the `end` of the configured window.
    pub unsafe fn set_len(&mut self, len: usize) {
        assert!(len <= self.cap);
        self.len = len;
    }

    /// Returns the inner contents of this `BytesMut` as a mutable slice
    ///
    /// This a slice of all bytes, including uninitialized memory
    pub unsafe fn as_raw(&mut self) -> &mut [u8] {
        slice::from_raw_parts_mut(self.ptr, self.cap)
    }

    /// Changes the starting index of this window to the index specified.
    ///
    /// # Panics
    ///
    /// This method will panic if `start` is out of bounds for the underlying
    /// slice.
    unsafe fn set_start(&mut self, start: usize) {
        assert!(start <= self.cap);
        debug_assert!(self.is_shared());
        debug_assert!(self.len <= self.cap);

        self.ptr = self.ptr.offset(start as isize);

        // TODO: This could probably be optimized with some bit fiddling
        if self.len >= start {
            self.len -= start;
        } else {
            self.len = 0;
        }

        self.cap -= start;
    }

    /// Changes the end index of this window to the index specified.
    ///
    /// # Panics
    ///
    /// This method will panic if `start` is out of bounds for the underlying
    /// slice.
    unsafe fn set_end(&mut self, end: usize) {
        assert!(end <= self.cap);
        debug_assert!(self.is_shared());

        self.cap = end;
        self.len = cmp::min(self.len, end);
    }

    /// Checks if it is safe to mutate the memory
    fn is_mut_safe(&mut self) -> bool {
        unsafe {
            (*self.arc.get()).as_mut()
                // Check if there is only one outstanding reference to the memory
                .map(|a| Arc::get_mut(a).is_some())
                // If there is no arc, then this is a unique pointer
                .unwrap_or(true)
        }
    }

    /// Increments the ref count. This should only be done if it is known that
    /// it can be done safely. As such, this fn is not public, instead other
    /// fns will use this one while maintaining the guarantees.
    fn shallow_clone(&self) -> BytesMut {
        let arc = unsafe {
            match *self.arc.get() {
                Some(ref arc) => {
                    // Already backed by an arc, just clone it
                    arc.clone()
                }
                None => {
                    // Promote this `Bytes` to an arc, and clone it
                    let v = Vec::from_raw_parts(self.ptr, self.len, self.cap);
                    let a = Arc::new(v);

                    *self.arc.get() = Some(a.clone());

                    a
                }
            }
        };

         BytesMut {
             arc: UnsafeCell::new(Some(arc)),
            .. *self
        }
    }

    fn is_shared(&self) -> bool {
        unsafe { (*self.arc.get()).is_some() }
    }
}

impl Drop for BytesMut {
    fn drop(&mut self) {
        if !self.is_shared() {
            unsafe {
                // Not shared, manually free
                let _ = Vec::from_raw_parts(self.ptr, self.len, self.cap);
            }
        }
    }
}

impl IntoBuf for BytesMut {
    type Buf = SliceBuf<Self>;

    fn into_buf(self) -> Self::Buf {
        SliceBuf::new(self)
    }
}

impl<'a> IntoBuf for &'a BytesMut {
    type Buf = SliceBuf<&'a BytesMut>;

    fn into_buf(self) -> Self::Buf {
        SliceBuf::new(self)
    }
}

impl AsRef<[u8]> for BytesMut {
    fn as_ref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.ptr, self.len) }
    }
}

impl ops::Deref for BytesMut {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl ops::DerefMut for BytesMut {
    fn deref_mut(&mut self) -> &mut [u8] {
        self.as_mut()
    }
}

impl From<Vec<u8>> for BytesMut {
    fn from(mut src: Vec<u8>) -> BytesMut {
        let len = src.len();
        let cap = src.capacity();
        let ptr = src.as_mut_ptr();

        mem::forget(src);

        BytesMut {
            ptr: ptr,
            len: len,
            cap: cap,
            arc: UnsafeCell::new(None),
        }
    }
}

impl<'a> From<&'a [u8]> for BytesMut {
    fn from(src: &'a [u8]) -> BytesMut {
        BytesMut::from_slice(src)
    }
}

impl PartialEq for BytesMut {
    fn eq(&self, other: &BytesMut) -> bool {
        **self == **other
    }
}

impl Eq for BytesMut {
}

impl fmt::Debug for BytesMut {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_ref(), fmt)
    }
}

unsafe impl Send for BytesMut {}

/*
 *
 * ===== PartialEq =====
 *
 */

impl PartialEq<[u8]> for BytesMut {
    fn eq(&self, other: &[u8]) -> bool {
        &**self == other
    }
}

impl PartialEq<BytesMut> for [u8] {
    fn eq(&self, other: &BytesMut) -> bool {
        *other == *self
    }
}

impl PartialEq<Vec<u8>> for BytesMut {
    fn eq(&self, other: &Vec<u8>) -> bool {
        *self == &other[..]
    }
}

impl PartialEq<BytesMut> for Vec<u8> {
    fn eq(&self, other: &BytesMut) -> bool {
        *other == *self
    }
}

impl<'a, T: ?Sized> PartialEq<&'a T> for BytesMut
    where BytesMut: PartialEq<T>
{
    fn eq(&self, other: &&'a T) -> bool {
        *self == **other
    }
}

impl<'a> PartialEq<BytesMut> for &'a [u8] {
    fn eq(&self, other: &BytesMut) -> bool {
        *other == *self
    }
}

impl PartialEq<[u8]> for Bytes {
    fn eq(&self, other: &[u8]) -> bool {
        self.inner == *other
    }
}

impl PartialEq<Bytes> for [u8] {
    fn eq(&self, other: &Bytes) -> bool {
        *other == *self
    }
}

impl PartialEq<Vec<u8>> for Bytes {
    fn eq(&self, other: &Vec<u8>) -> bool {
        *self == &other[..]
    }
}

impl PartialEq<Bytes> for Vec<u8> {
    fn eq(&self, other: &Bytes) -> bool {
        *other == *self
    }
}

impl<'a> PartialEq<Bytes> for &'a [u8] {
    fn eq(&self, other: &Bytes) -> bool {
        *other == *self
    }
}

impl<'a, T: ?Sized> PartialEq<&'a T> for Bytes
    where Bytes: PartialEq<T>
{
    fn eq(&self, other: &&'a T) -> bool {
        *self == **other
    }
}

impl Clone for BytesMut {
    fn clone(&self) -> BytesMut {
        let mut v = Vec::with_capacity(self.len());
        v.extend_from_slice(&self[..]);

        BytesMut::from(v)
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate rand;

pub const DEFAULT_ENGLISH_DICTIONARY_PATH: &'static str = "/usr/share/dict/words";

#[derive(Debug)]
pub struct EnglishPasswordOptions {
    pub num_words: u8,
    pub dictionary_path: String,
}

#[derive(Debug)]
pub struct KanaPasswordOptions {
    pub syllable_counts: Vec<u8>,
}

pub enum PasswordOptions {
    English(EnglishPasswordOptions),
    Japanese(KanaPasswordOptions),
}

mod args {
    use crate::{EnglishPasswordOptions, KanaPasswordOptions, PasswordOptions};
    use clap::{value_t, values_t};

    // Aborts this process on error.
    pub fn parse_args() -> PasswordOptions {
        let matches = clap::App::new("xkpw")
            .version("0.1.0")
            .author("j39m")
            .about("Generates passwords")
            .subcommand(
                clap::SubCommand::with_name("en")
                    .about("generates dictionary passwords in English")
                    .arg(clap::Arg::with_name("num-words").required(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("jp")
                    .about("generates random strings of Japanese syllables")
                    .arg(
                        clap::Arg::with_name("syllable-counts")
                            .required(true)
                            .multiple(true),
                    ),
            )
            .get_matches();

        match matches.subcommand() {
            ("en", Some(en_matches)) => {
                return crate::PasswordOptions::English(crate::EnglishPasswordOptions {
                    num_words: clap::value_t!(en_matches, "num-words", u8)
                        .unwrap_or_else(|e| e.exit()),
                    dictionary_path: crate::DEFAULT_ENGLISH_DICTIONARY_PATH.to_owned(),
                })
            }
            ("jp", Some(jp_matches)) => {
                return crate::PasswordOptions::Japanese(crate::KanaPasswordOptions {
                    syllable_counts: clap::values_t!(jp_matches, "syllable-counts", u8)
                        .unwrap_or_else(|e| e.exit()),
                })
            }
            _ => (),
        }
        crate::PasswordOptions::Japanese(crate::KanaPasswordOptions {
            syllable_counts: vec![4, 3, 3, 3],
        })
    }
} // mod args

mod helpers {
    use rand::seq::SliceRandom;
    use std::convert::TryInto;
    use std::io::Read;

    // Reads the dictionary at |path| and returns a linewise vector of
    // its contents.
    fn ingest_english_dictionary(path: &std::path::Path) -> std::io::Result<Vec<String>> {
        let mut file = std::fs::File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(contents
            .lines()
            .map(|word| word.trim().to_lowercase())
            .collect())
    }

    // Returns 1 if we fail to read the word dictionary.
    fn print_english_password(options: crate::EnglishPasswordOptions) -> i32 {
        let words = match ingest_english_dictionary(std::path::Path::new(&options.dictionary_path))
        {
            Ok(result) => result,
            Err(error) => {
                eprintln!("Error reading dictionary: {}", error);
                return 1;
            }
        };
        let mut rng = &mut rand::thread_rng();
        let selection: Vec<&String> = words
            .choose_multiple(&mut rng, options.num_words.try_into().unwrap())
            .collect();

        let mut iter = selection.iter();
        if let Some(word) = iter.next() {
            print!("{}", word);
            for word in iter {
                print!(" {}", word);
            }
            print!("\n");
        }
        0
    }

    fn print_kana_password(options: crate::KanaPasswordOptions) {
        eprintln!("XXX(j39m): FIX ME");
    }

    pub fn main() -> i32 {
        let options = crate::args::parse_args();
        match options {
            crate::PasswordOptions::English(options) => return print_english_password(options),
            crate::PasswordOptions::Japanese(options) => print_kana_password(options),
        }
        0
    }
} // mod helpers

fn main() {
    std::process::exit(crate::helpers::main());
}
<commit_msg>xkpw: complete Rust port<commit_after>extern crate clap;
extern crate rand;

pub const DEFAULT_ENGLISH_DICTIONARY_PATH: &'static str = "/usr/share/dict/words";

#[derive(Debug)]
pub struct EnglishPasswordOptions {
    pub num_words: u8,
    pub dictionary_path: String,
}

#[derive(Debug)]
pub struct KanaPasswordOptions {
    pub syllable_counts: Vec<u8>,
}

pub enum PasswordOptions {
    English(EnglishPasswordOptions),
    Japanese(KanaPasswordOptions),
}

mod args {
    use clap::{value_t, values_t};

    // Aborts this process on error.
    pub fn parse_args() -> crate::PasswordOptions {
        let matches = clap::App::new("xkpw")
            .version("0.1.0")
            .author("j39m")
            .about("Generates passwords")
            .subcommand(
                clap::SubCommand::with_name("en")
                    .about("generates dictionary passwords in English")
                    .arg(clap::Arg::with_name("num-words").required(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("jp")
                    .about("generates random strings of Japanese syllables")
                    .arg(
                        clap::Arg::with_name("syllable-counts")
                            .required(true)
                            .multiple(true),
                    ),
            )
            .get_matches();

        match matches.subcommand() {
            ("en", Some(en_matches)) => {
                return crate::PasswordOptions::English(crate::EnglishPasswordOptions {
                    num_words: clap::value_t!(en_matches, "num-words", u8)
                        .unwrap_or_else(|e| e.exit()),
                    dictionary_path: crate::DEFAULT_ENGLISH_DICTIONARY_PATH.to_owned(),
                })
            }
            ("jp", Some(jp_matches)) => {
                return crate::PasswordOptions::Japanese(crate::KanaPasswordOptions {
                    syllable_counts: clap::values_t!(jp_matches, "syllable-counts", u8)
                        .unwrap_or_else(|e| e.exit()),
                })
            }
            _ => (),
        }
        crate::PasswordOptions::Japanese(crate::KanaPasswordOptions {
            syllable_counts: vec![4, 3, 3, 3],
        })
    }
} // mod args

mod kana {
    pub const BASE: &'static [&str] = &[
        "a", "i", "u", "e", "o", "ka", "ki", "ku", "ke", "ko", "sa", "shi", "su", "se", "so", "ta",
        "chi", "tsu", "te", "to", "na", "ni", "nu", "ne", "no", "ha", "hi", "hu", "he", "ho", "ma",
        "mi", "mu", "me", "mo", "ya", "yu", "yo", "ra", "ri", "ru", "re", "ro", "wa", "wo",
    ];

    pub const DIGRAPHS: &'static [&str] = &[
        "kya", "kyu", "kyo", "sha", "shu", "sho", "cha", "chu", "cho", "nya", "nyu", "nyo", "hya",
        "hyu", "hyo", "mya", "myu", "myo", "rya", "ryu", "ryo",
    ];

    pub const DIACRITICS: &'static [&str] = &[
        "ga", "gi", "gu", "ge", "go", "za", "ji", "zu", "ze", "zo", "da", "de", "do", "ba", "bi",
        "bu", "be", "bo", "pa", "pi", "pu", "pe", "po",
    ];

    pub const DIGRAPHS_WITH_DIACRITICS: &'static [&str] = &[
        "gya", "gyu", "gyo", "ja", "ju", "jo", "bya", "byu", "byo", "pya", "pyu", "pyo",
    ];

    fn all() -> Vec<&'static str> {
        let mut all_kana: Vec<&'static str> = Vec::new();
        all_kana.extend(BASE);
        all_kana.extend(DIGRAPHS);
        all_kana.extend(DIACRITICS);
        all_kana.extend(DIGRAPHS_WITH_DIACRITICS);
        all_kana
    }

    fn simple() -> Vec<&'static str> {
        let mut simple_kana: Vec<&'static str> = Vec::new();
        simple_kana.extend(BASE);
        simple_kana.extend(DIACRITICS);
        simple_kana
    }

    pub fn get(use_simple: bool) -> Vec<&'static str> {
        match use_simple {
            true => simple(),
            false => all(),
        }
    }
} // mod kana

mod helpers {
    use rand::seq::SliceRandom;
    use std::convert::TryInto;
    use std::io::Read;

    // Reads the dictionary at |path| and returns a linewise vector of
    // its contents.
    fn ingest_english_dictionary(path: &std::path::Path) -> std::io::Result<Vec<String>> {
        let mut file = std::fs::File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(contents
            .lines()
            .map(|word| word.trim().to_lowercase())
            .collect())
    }

    // Assumes ownership of a Vector of owned |words| and prints them
    // separated by spaces.
    fn print_words(words: Vec<String>) {
        let mut iter = words.into_iter();
        if let Some(word) = iter.next() {
            print!("{}", word);
            for word in iter {
                print!(" {}", word);
            }
            print!("\n");
        }
    }

    // Returns 1 if we fail to read the word dictionary.
    fn print_english_password(options: crate::EnglishPasswordOptions) -> i32 {
        let all_words =
            match ingest_english_dictionary(std::path::Path::new(&options.dictionary_path)) {
                Ok(result) => result,
                Err(error) => {
                    eprintln!("Error reading dictionary: {}", error);
                    return 1;
                }
            };
        let mut rng = &mut rand::thread_rng();
        let selection: Vec<String> = all_words
            .choose_multiple(&mut rng, options.num_words.try_into().unwrap())
            .map(|borrowed| borrowed.to_owned())
            .collect();

        print_words(selection);
        0
    }

    // Builds a single random pseudo-Japanese word from |kana_set|.
    fn build_kana_word(kana_set: &Vec<&'static str>, syllable_count: &u8) -> String {
        let mut collected_kana: Vec<&'static str> = Vec::new();
        let mut rng = &mut rand::thread_rng();
        for _ in 0..*syllable_count {
            collected_kana.push(kana_set.choose(&mut rng).unwrap());
        }
        collected_kana.join("")
    }

    // Builds random pseudo-Japanese words from |kana_set|, observing
    // the word lengths specified by |options|.
    fn build_kana_words(
        kana_set: Vec<&'static str>,
        options: crate::KanaPasswordOptions,
    ) -> Vec<String> {
        options
            .syllable_counts
            .iter()
            .map(|count| build_kana_word(&kana_set, count))
            .collect()
    }

    // Builds a vector of owned kana words, maps these to a vector of
    // borrowed kana words, and then prints the same.
    fn print_kana_password(options: crate::KanaPasswordOptions) {
        print_words(build_kana_words(crate::kana::get(true), options));
    }

    pub fn main() -> i32 {
        let options = crate::args::parse_args();
        match options {
            crate::PasswordOptions::English(options) => return print_english_password(options),
            crate::PasswordOptions::Japanese(options) => print_kana_password(options),
        }
        0
    }
} // mod helpers

fn main() {
    std::process::exit(crate::helpers::main());
}
<|endoftext|>


<commit_before>use std::fmt;

use features::Features;

/// A sentence with the CoNLL-X annotation layers.
pub type Sentence = Vec<Token>;

/// This data type is a small wrapper around `Vec<Token>` that implements
/// the `Display` trait. The sentence will formatted in CoNLL-X format.
pub struct DisplaySentence<'a>(pub &'a Sentence);

impl<'a> fmt::Display for DisplaySentence<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let last_id = self.0.len() - 1;

        for (id, token) in self.0.iter().enumerate() {
            if id == last_id {
                write!(f, "{}\t{}", id + 1, token)?
            } else {
                write!(f, "{}\t{}\n", id + 1, token)?
            }
        }

        Ok(())
    }
}

/// A builder for `Token`s.
///
/// The `Token` type stores a CoNLL-X token. However, since this format
/// permits a large number of fields, construction of a token can get
/// tedious. This builder provides a fluent interface for creating `Token`s.
pub struct TokenBuilder {
    token: Token,
}

impl TokenBuilder {
    /// Create a `Token` builder with all non-form fields set to absent.
    pub fn new<S>(form: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        TokenBuilder {
            token: Token::new(form),
        }
    }

    /// Set the word form or punctuation symbol.
    pub fn form<S>(mut self, form: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_form(form);
        self
    }

    /// Set the lemma or stem of the word form.
    pub fn lemma<S>(mut self, lemma: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_lemma(Some(lemma));
        self
    }

    /// Set the coarse-grained part-of-speech tag.
    pub fn cpos<S>(mut self, cpos: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_cpos(Some(cpos));
        self
    }

    /// Set the fine-grained part-of-speech tag.
    pub fn pos<S>(mut self, pos: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_pos(Some(pos));
        self
    }

    /// Set the syntactic and/or morphological features of the token.
    pub fn features(mut self, features: Features) -> TokenBuilder {
        self.token.set_features(Some(features));
        self
    }

    /// Set the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn head(mut self, head: usize) -> TokenBuilder {
        self.token.set_head(Some(head));
        self
    }

    /// Set the dependency relation to the head of this token.
    pub fn head_rel<S>(mut self, head_rel: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_head_rel(Some(head_rel));
        self
    }

    /// Set the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn p_head(mut self, p_head: usize) -> TokenBuilder {
        self.token.set_p_head(Some(p_head));
        self
    }

    /// Set the dependency relation to the projective head of this token.
    pub fn p_head_rel<S>(mut self, p_head_rel: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_p_head_rel(Some(p_head_rel));
        self
    }

    pub fn token(self) -> Token {
        self.token
    }
}

/// A token with the CoNLL-X annotation layers.
///
/// The fields of CoNLLX tokens are described at:
///
/// http://ilk.uvt.nl/conll/
///
/// This type provides exactly the same fields, except for the ID field
/// (since it can be derived from the sentence position of the token).
/// If a particular field is absent (*_* in the CoNLL-X format), its
/// value is `None`.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Token {
    form: String,
    lemma: Option<String>,
    cpos: Option<String>,
    pos: Option<String>,
    features: Option<Features>,
    head: Option<usize>,
    head_rel: Option<String>,
    p_head: Option<usize>,
    p_head_rel: Option<String>,
}

impl Token {
    /// Create a new token where all the non-form fields are absent.
    pub fn new<S>(form: S) -> Token
    where
        S: Into<String>,
    {
        Token {
            form: form.into(),
            lemma: None,
            cpos: None,
            pos: None,
            features: None,
            head: None,
            head_rel: None,
            p_head: None,
            p_head_rel: None,
        }
    }

    /// Get the word form or punctuation symbol.
    pub fn form(&self) -> &str {
        self.form.as_ref()
    }

    /// Get the lemma or stem of the word form.
    pub fn lemma(&self) -> Option<&str> {
        self.lemma.as_ref().map(String::as_ref)
    }

    /// Get the coarse-grained part-of-speech tag.
    pub fn cpos(&self) -> Option<&str> {
        self.cpos.as_ref().map(String::as_ref)
    }

    /// Get the fine-grained part-of-speech tag.
    pub fn pos(&self) -> Option<&str> {
        self.pos.as_ref().map(String::as_ref)
    }

    /// Get the syntactic and/or morphological features of the token.
    pub fn features(&self) -> Option<&Features> {
        self.features.as_ref()
    }

    /// Get the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn head(&self) -> Option<usize> {
        self.head
    }

    /// Get the dependency relation to the head of this token.
    pub fn head_rel(&self) -> Option<&str> {
        self.head_rel.as_ref().map(String::as_ref)
    }

    /// Get the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn p_head(&self) -> Option<usize> {
        self.p_head
    }

    /// Get the dependency relation to the projective head of this token.
    pub fn p_head_rel(&self) -> Option<&str> {
        self.p_head_rel.as_ref().map(String::as_ref)
    }

    /// Set the word form or punctuation symbol.
    pub fn set_form<S>(&mut self, form: S)
    where
        S: Into<String>,
    {
        self.form = form.into()
    }

    /// Set the lemma or stem of the word form.
    pub fn set_lemma<S>(&mut self, lemma: Option<S>)
    where
        S: Into<String>,
    {
        self.lemma = lemma.map(|i| i.into())
    }

    /// Set the coarse-grained part-of-speech tag.
    pub fn set_cpos<S>(&mut self, cpos: Option<S>)
    where
        S: Into<String>,
    {
        self.cpos = cpos.map(|i| i.into())
    }

    /// Set the fine-grained part-of-speech tag.
    pub fn set_pos<S>(&mut self, pos: Option<S>)
    where
        S: Into<String>,
    {
        self.pos = pos.map(|i| i.into())
    }

    /// Set the syntactic and/or morphological features of the token.
    pub fn set_features(&mut self, features: Option<Features>) {
        self.features = features
    }

    /// Set the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn set_head(&mut self, head: Option<usize>) {
        self.head = head
    }

    /// Set the dependency relation to the head of this token.
    pub fn set_head_rel<S>(&mut self, head_rel: Option<S>)
    where
        S: Into<String>,
    {
        self.head_rel = head_rel.map(|i| i.into())
    }

    /// Set the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn set_p_head(&mut self, p_head: Option<usize>) {
        self.p_head = p_head
    }

    /// Set the dependency relation to the projective head of this token.
    pub fn set_p_head_rel<S>(&mut self, p_head_rel: Option<S>)
    where
        S: Into<String>,
    {
        self.p_head_rel = p_head_rel.map(|i| i.into())
    }
}

pub const EMPTY_TOKEN: &'static str = "_";

impl fmt::Display for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let head_str = self.head.as_ref().map(|n| n.to_string());
        let p_head_str = self.p_head.as_ref().map(|n| n.to_string());

        write!(
            f,
            "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
            self.form.as_str(),
            self.lemma
                .as_ref()
                .map(|s| s.as_ref())
                .unwrap_or(EMPTY_TOKEN),
            self.cpos
                .as_ref()
                .map(|s| s.as_ref())
                .unwrap_or(EMPTY_TOKEN),
            self.pos.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
            self.features
                .as_ref()
                .map(|s| s.as_str())
                .unwrap_or(EMPTY_TOKEN),
            head_str.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
            self.head_rel
                .as_ref()
                .map(|s| s.as_ref())
                .unwrap_or(EMPTY_TOKEN),
            p_head_str
                .as_ref()
                .map(|s| s.as_ref())
                .unwrap_or(EMPTY_TOKEN),
            self.p_head_rel
                .as_ref()
                .map(|s| s.as_ref())
                .unwrap_or(EMPTY_TOKEN),
        )
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use super::{Features, Token, TokenBuilder};

    fn token_with_features() -> Vec<Token> {
        vec![
            TokenBuilder::new("Gilles")
                .lemma("Gilles")
                .cpos("N")
                .pos("NE")
                .features(Features::from_string(
                    "case:nominative|number:singular|gender:masculine",
                ))
                .head(0)
                .head_rel("ROOT")
                .token(),
            TokenBuilder::new("Deleuze")
                .lemma("Deleuze")
                .cpos("N")
                .pos("NE")
                .features(Features::from_string("nominative|singular|masculine"))
                .head(1)
                .head_rel("APP")
                .token(),
        ]
    }

    fn features_correct() -> Vec<BTreeMap<String, Option<String>>> {
        let mut correct1 = BTreeMap::new();
        correct1.insert("case".to_owned(), Some("nominative".to_owned()));
        correct1.insert("number".to_owned(), Some("singular".to_owned()));
        correct1.insert("gender".to_owned(), Some("masculine".to_owned()));

        let mut correct2 = BTreeMap::new();
        correct2.insert("nominative".to_owned(), None);
        correct2.insert("singular".to_owned(), None);
        correct2.insert("masculine".to_owned(), None);

        vec![correct1, correct2]
    }

    #[test]
    fn features() {
        let tokens = token_with_features();
        let features = features_correct();

        for (token, correct) in tokens.iter().zip(features) {
            let kv = token.features().as_ref().unwrap().as_map();
            assert_eq!(&correct, kv);
        }
    }
}
<commit_msg>'automatic links' in Pulldown need <> around them.<commit_after>use std::fmt;

use features::Features;

/// A sentence with the CoNLL-X annotation layers.
pub type Sentence = Vec<Token>;

/// This data type is a small wrapper around `Vec<Token>` that implements
/// the `Display` trait. The sentence will formatted in CoNLL-X format.
pub struct DisplaySentence<'a>(pub &'a Sentence);

impl<'a> fmt::Display for DisplaySentence<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let last_id = self.0.len() - 1;

        for (id, token) in self.0.iter().enumerate() {
            if id == last_id {
                write!(f, "{}\t{}", id + 1, token)?
            } else {
                write!(f, "{}\t{}\n", id + 1, token)?
            }
        }

        Ok(())
    }
}

/// A builder for `Token`s.
///
/// The `Token` type stores a CoNLL-X token. However, since this format
/// permits a large number of fields, construction of a token can get
/// tedious. This builder provides a fluent interface for creating `Token`s.
pub struct TokenBuilder {
    token: Token,
}

impl TokenBuilder {
    /// Create a `Token` builder with all non-form fields set to absent.
    pub fn new<S>(form: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        TokenBuilder {
            token: Token::new(form),
        }
    }

    /// Set the word form or punctuation symbol.
    pub fn form<S>(mut self, form: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_form(form);
        self
    }

    /// Set the lemma or stem of the word form.
    pub fn lemma<S>(mut self, lemma: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_lemma(Some(lemma));
        self
    }

    /// Set the coarse-grained part-of-speech tag.
    pub fn cpos<S>(mut self, cpos: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_cpos(Some(cpos));
        self
    }

    /// Set the fine-grained part-of-speech tag.
    pub fn pos<S>(mut self, pos: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_pos(Some(pos));
        self
    }

    /// Set the syntactic and/or morphological features of the token.
    pub fn features(mut self, features: Features) -> TokenBuilder {
        self.token.set_features(Some(features));
        self
    }

    /// Set the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn head(mut self, head: usize) -> TokenBuilder {
        self.token.set_head(Some(head));
        self
    }

    /// Set the dependency relation to the head of this token.
    pub fn head_rel<S>(mut self, head_rel: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_head_rel(Some(head_rel));
        self
    }

    /// Set the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn p_head(mut self, p_head: usize) -> TokenBuilder {
        self.token.set_p_head(Some(p_head));
        self
    }

    /// Set the dependency relation to the projective head of this token.
    pub fn p_head_rel<S>(mut self, p_head_rel: S) -> TokenBuilder
    where
        S: Into<String>,
    {
        self.token.set_p_head_rel(Some(p_head_rel));
        self
    }

    pub fn token(self) -> Token {
        self.token
    }
}

/// A token with the CoNLL-X annotation layers.
///
/// The fields of CoNLLX tokens are described at:
///
/// <http://ilk.uvt.nl/conll/>
///
/// This type provides exactly the same fields, except for the ID field
/// (since it can be derived from the sentence position of the token).
/// If a particular field is absent (*_* in the CoNLL-X format), its
/// value is `None`.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Token {
    form: String,
    lemma: Option<String>,
    cpos: Option<String>,
    pos: Option<String>,
    features: Option<Features>,
    head: Option<usize>,
    head_rel: Option<String>,
    p_head: Option<usize>,
    p_head_rel: Option<String>,
}

impl Token {
    /// Create a new token where all the non-form fields are absent.
    pub fn new<S>(form: S) -> Token
    where
        S: Into<String>,
    {
        Token {
            form: form.into(),
            lemma: None,
            cpos: None,
            pos: None,
            features: None,
            head: None,
            head_rel: None,
            p_head: None,
            p_head_rel: None,
        }
    }

    /// Get the word form or punctuation symbol.
    pub fn form(&self) -> &str {
        self.form.as_ref()
    }

    /// Get the lemma or stem of the word form.
    pub fn lemma(&self) -> Option<&str> {
        self.lemma.as_ref().map(String::as_ref)
    }

    /// Get the coarse-grained part-of-speech tag.
    pub fn cpos(&self) -> Option<&str> {
        self.cpos.as_ref().map(String::as_ref)
    }

    /// Get the fine-grained part-of-speech tag.
    pub fn pos(&self) -> Option<&str> {
        self.pos.as_ref().map(String::as_ref)
    }

    /// Get the syntactic and/or morphological features of the token.
    pub fn features(&self) -> Option<&Features> {
        self.features.as_ref()
    }

    /// Get the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn head(&self) -> Option<usize> {
        self.head
    }

    /// Get the dependency relation to the head of this token.
    pub fn head_rel(&self) -> Option<&str> {
        self.head_rel.as_ref().map(String::as_ref)
    }

    /// Get the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn p_head(&self) -> Option<usize> {
        self.p_head
    }

    /// Get the dependency relation to the projective head of this token.
    pub fn p_head_rel(&self) -> Option<&str> {
        self.p_head_rel.as_ref().map(String::as_ref)
    }

    /// Set the word form or punctuation symbol.
    pub fn set_form<S>(&mut self, form: S)
    where
        S: Into<String>,
    {
        self.form = form.into()
    }

    /// Set the lemma or stem of the word form.
    pub fn set_lemma<S>(&mut self, lemma: Option<S>)
    where
        S: Into<String>,
    {
        self.lemma = lemma.map(|i| i.into())
    }

    /// Set the coarse-grained part-of-speech tag.
    pub fn set_cpos<S>(&mut self, cpos: Option<S>)
    where
        S: Into<String>,
    {
        self.cpos = cpos.map(|i| i.into())
    }

    /// Set the fine-grained part-of-speech tag.
    pub fn set_pos<S>(&mut self, pos: Option<S>)
    where
        S: Into<String>,
    {
        self.pos = pos.map(|i| i.into())
    }

    /// Set the syntactic and/or morphological features of the token.
    pub fn set_features(&mut self, features: Option<Features>) {
        self.features = features
    }

    /// Set the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn set_head(&mut self, head: Option<usize>) {
        self.head = head
    }

    /// Set the dependency relation to the head of this token.
    pub fn set_head_rel<S>(&mut self, head_rel: Option<S>)
    where
        S: Into<String>,
    {
        self.head_rel = head_rel.map(|i| i.into())
    }

    /// Set the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn set_p_head(&mut self, p_head: Option<usize>) {
        self.p_head = p_head
    }

    /// Set the dependency relation to the projective head of this token.
    pub fn set_p_head_rel<S>(&mut self, p_head_rel: Option<S>)
    where
        S: Into<String>,
    {
        self.p_head_rel = p_head_rel.map(|i| i.into())
    }
}

pub const EMPTY_TOKEN: &'static str = "_";

impl fmt::Display for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let head_str = self.head.as_ref().map(|n| n.to_string());
        let p_head_str = self.p_head.as_ref().map(|n| n.to_string());

        write!(
            f,
            "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
            self.form.as_str(),
            self.lemma
                .as_ref()
                .map(|s| s.as_ref())
                .unwrap_or(EMPTY_TOKEN),
            self.cpos
                .as_ref()
                .map(|s| s.as_ref())
                .unwrap_or(EMPTY_TOKEN),
            self.pos.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
            self.features
                .as_ref()
                .map(|s| s.as_str())
                .unwrap_or(EMPTY_TOKEN),
            head_str.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
            self.head_rel
                .as_ref()
                .map(|s| s.as_ref())
                .unwrap_or(EMPTY_TOKEN),
            p_head_str
                .as_ref()
                .map(|s| s.as_ref())
                .unwrap_or(EMPTY_TOKEN),
            self.p_head_rel
                .as_ref()
                .map(|s| s.as_ref())
                .unwrap_or(EMPTY_TOKEN),
        )
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use super::{Features, Token, TokenBuilder};

    fn token_with_features() -> Vec<Token> {
        vec![
            TokenBuilder::new("Gilles")
                .lemma("Gilles")
                .cpos("N")
                .pos("NE")
                .features(Features::from_string(
                    "case:nominative|number:singular|gender:masculine",
                ))
                .head(0)
                .head_rel("ROOT")
                .token(),
            TokenBuilder::new("Deleuze")
                .lemma("Deleuze")
                .cpos("N")
                .pos("NE")
                .features(Features::from_string("nominative|singular|masculine"))
                .head(1)
                .head_rel("APP")
                .token(),
        ]
    }

    fn features_correct() -> Vec<BTreeMap<String, Option<String>>> {
        let mut correct1 = BTreeMap::new();
        correct1.insert("case".to_owned(), Some("nominative".to_owned()));
        correct1.insert("number".to_owned(), Some("singular".to_owned()));
        correct1.insert("gender".to_owned(), Some("masculine".to_owned()));

        let mut correct2 = BTreeMap::new();
        correct2.insert("nominative".to_owned(), None);
        correct2.insert("singular".to_owned(), None);
        correct2.insert("masculine".to_owned(), None);

        vec![correct1, correct2]
    }

    #[test]
    fn features() {
        let tokens = token_with_features();
        let features = features_correct();

        for (token, correct) in tokens.iter().zip(features) {
            let kv = token.features().as_ref().unwrap().as_map();
            assert_eq!(&correct, kv);
        }
    }
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{thread, time};
use std::thread::JoinHandle;

use instruction::Instruction;
use peripherals::Peripherals;

use rand::{thread_rng, Rng};

const FONT_BASE_ADDR: usize = 0x0;
const NUM_FONTS: usize = 16;
const FONT_SIZE: usize = 5;
const FONT_MAP: [u8; NUM_FONTS * FONT_SIZE] =
    [0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0,
     0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0,
     0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0,
     0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0,
     0xF0, 0x80, 0x80, 0x80, 0xF0, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0xF0, 0x80, 0xF0, 0x80, 0xF0,
     0xF0, 0x80, 0xF0, 0x80, 0x80];

pub struct Chip8 {
    mem: Vec<u8>,
    reg_v: Vec<u8>,
    reg_i: u16,
    reg_delay_timer: Arc<AtomicUsize>,
    reg_sound_timer: u8,
    pc: usize,
    sp: usize,
    stack: Vec<usize>,
}

impl Chip8 {
    pub fn new(rom: &Vec<u8>) -> Chip8 {
        let mut chip8 = Chip8 {
            mem: vec![0; 0xFFF],
            reg_v: vec![0; 16],
            reg_i: 0,
            reg_delay_timer: Arc::new(AtomicUsize::new(0)),
            reg_sound_timer: 0,
            pc: 0x200,
            sp: 0,
            stack: vec![0; 16],
        };
        chip8.load_fonts();
        chip8.load_rom(rom);
        chip8
    }

    fn load_fonts(&mut self) {
        for i in FONT_BASE_ADDR..FONT_MAP.len() {
            self.mem[i] = FONT_MAP[i - FONT_BASE_ADDR]
        }
    }

    fn load_rom(&mut self, rom: &Vec<u8>) {
        for (b, buf_i) in rom.iter().enumerate() {
            self.mem[0x200 + b] = *buf_i;
        }
    }

    pub fn step(&mut self, peripherals: &mut Peripherals) {
        let hi_nibble = self.mem[self.pc] as u16;
        let lo_nibble = self.mem[self.pc + 1] as u16;
        let opcode = (hi_nibble << 8) | lo_nibble;
        match Instruction::try_from(opcode) {
            Err(msg) => panic!("Error decoding instruction at 0x{0:03x}: {1}", self.pc, msg),
            Ok(instruction) => self.step_instruction(instruction, peripherals),
        }
    }

    fn memory_read(&self, pos: usize) -> u8 {
        self.mem[pos]
    }

    fn memory_write(&mut self, pos: usize, data: u8) {
        self.mem[pos] = data;
        // println!("[W][0x{:03x}] 0x{:03x}", pos, data);
    }

    fn step_instruction(&mut self, instruction: Instruction, peripherals: &mut Peripherals) {
        match instruction {
            Instruction::Cls => peripherals.video_engine.cls(),
            Instruction::Ret => {
                assert!(self.sp > 0);
                self.sp -= 1;
                let old_pc = self.stack[self.sp];
                println!("Resuming execution at PC 0x{:x}", old_pc);
                self.pc = old_pc; // Jump to the instruction immediately after
            }
            Instruction::Jmp { addr } => self.pc = addr - 2, // Correct for pc increment later
            Instruction::Jsr { addr } => {
                self.stack[self.sp] = self.pc;
                self.sp += 1;
                self.pc = addr - 2
            } // Correct for pc increment later
            Instruction::Mov { vr, k } => self.reg_v[vr] = k,
            Instruction::Movr { vr, vy } => self.reg_v[vr] = self.reg_v[vy],
            Instruction::And { vr, vy } => self.reg_v[vr] &= self.reg_v[vy],
            Instruction::Shr { vr } => {
                let current_val = self.reg_v[vr];
                self.reg_v[0xF] = current_val & 1;
                self.reg_v[vr] = current_val >> 1;
            }
            Instruction::Skner { vr, vy } => {
                if self.reg_v[vr] != self.reg_v[vy] {
                    self.pc += 2;
                }
            }
            Instruction::Skeq { vr, k } => {
                if self.reg_v[vr] == k {
                    self.pc += 2
                }
            }
            Instruction::Skne { vr, k } => {
                if self.reg_v[vr] != k {
                    self.pc += 2
                }
            }
            Instruction::Add { vr, k } => {
                let old_val = self.reg_v[vr];
                self.reg_v[vr] = old_val.wrapping_add(k);
            }
            Instruction::Addr { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_r.overflowing_add(old_y);
                if overflow {
                    self.reg_v[0xF] = 1
                } else {
                    self.reg_v[0xF] = 0
                }
                self.reg_v[vr] = result;
            }
            Instruction::Mvi { k } => self.reg_i = k,
            Instruction::Rnd { vr, k } => {
                let mut buffer = [0u8; 1];
                thread_rng().fill_bytes(&mut buffer);
                self.reg_v[vr] = buffer[0] & k;
            }
            Instruction::Sprite { rx, ry, s } => {
                let x = self.reg_v[rx] as usize;
                let y = self.reg_v[ry] as usize;
                let height = s;
                self.reg_v[0xF] = 0;
                for yline in 0..height {
                    let mem_pos = self.reg_i as usize + yline as usize;
                    let pixel = self.memory_read(mem_pos);
                    for xline in 0..8 {
                        if pixel & (0x80 >> xline) != 0 {
                            let collision = peripherals.video_engine
                                .set_pixel_to_1(x + xline, y + yline);
                            if collision {
                                self.reg_v[0xF] = 1;
                            }
                        }

                    }
                }
            }
            Instruction::Skp { k } => {
                println!("Skipping if key {:x} is pressed", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => self.pc += 2,
                    _ => {}
                }
            }
            Instruction::Sknp { k } => {
                println!("Skipping if key {:x} is not pressed", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => {}
                    _ => self.pc += 2,
                }
            }
            Instruction::Key { vr } => {
                println!("Waiting for a key to be pressed");
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) => {
                        println!(" ... Got {:x}", x);
                        self.reg_v[vr] = x
                    }
                    _ => {
                        println!(" ... Waiting more");
                        self.pc -= 2; // Emulate a SLEEP
                    }
                }

            }
            Instruction::Adi { vr } => {
                self.reg_i += self.reg_v[vr] as u16;
            }
            Instruction::Font { vr } => {
                let character = self.reg_v[vr] as usize;
                self.reg_i = (FONT_BASE_ADDR + (character * FONT_SIZE)) as u16;
                println!("Font draw for character: {:x}", character);
            }
            Instruction::Bcd { vr } => {
                let value = self.reg_v[vr];
                println!("BCD DECODING OF {}", value);
                let i = self.reg_i as usize;
                self.mem[i] = value / 100;
                self.mem[i + 1] = (value / 10) % 10;
                self.mem[i + 2] = (value % 100) % 100;
            }
            Instruction::Str { vr } => {
                for idx in 0..(vr + 1) {
                    let target_pos = self.reg_i as usize + idx;
                    let data = self.reg_v[idx];
                    self.memory_write(target_pos, data);
                }
            }
            Instruction::Ldr { vr } => {
                for idx in 0..(vr + 1) {
                    self.reg_v[idx] = self.memory_read(self.reg_i as usize + idx)
                }
            }
            Instruction::Gdelay { vr } => {
                let amount = self.reg_delay_timer();
                self.reg_v[vr] = amount;
            }
            Instruction::Sdelay { vr } => {
                let amount = self.reg_v[vr];
                self.reg_delay_timer.store((amount + 1) as _, Ordering::SeqCst);
                let timer_clone = self.reg_delay_timer.clone();
                thread::spawn(move || loop {
                    let ticks_left = timer_clone.fetch_sub(1, Ordering::SeqCst) - 1;
                    if ticks_left > 0 {
                        println!("Still {} ticks left", ticks_left);
                        thread::sleep(time::Duration::from_millis(1000 / 60));
                    } else {
                        break;
                    }
                });
            }
        }
        self.pc += 2;
    }

    pub fn pc(&self) -> usize {
        self.pc
    }

    pub fn mem(&self) -> &Vec<u8> {
        &self.mem
    }

    pub fn reg_v(&self) -> &Vec<u8> {
        &self.reg_v
    }

    pub fn reg_i(&self) -> u16 {
        self.reg_i
    }

    pub fn reg_delay_timer(&self) -> u8 {
        self.reg_delay_timer.load(Ordering::SeqCst) as _
    }

    pub fn reg_sound_timer(&self) -> u8 {
        self.reg_sound_timer
    }

    pub fn stack(&self) -> &Vec<usize> {
        &self.stack
    }

    pub fn sp(&self) -> usize {
        self.sp
    }
}
<commit_msg>Fix BCD decoding<commit_after>use std::convert::TryFrom;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{thread, time};
use std::thread::JoinHandle;

use instruction::Instruction;
use peripherals::Peripherals;

use rand::{thread_rng, Rng};

const FONT_BASE_ADDR: usize = 0x0;
const NUM_FONTS: usize = 16;
const FONT_SIZE: usize = 5;
const FONT_MAP: [u8; NUM_FONTS * FONT_SIZE] =
    [0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0,
     0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0,
     0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0,
     0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0,
     0xF0, 0x80, 0x80, 0x80, 0xF0, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0xF0, 0x80, 0xF0, 0x80, 0xF0,
     0xF0, 0x80, 0xF0, 0x80, 0x80];

pub struct Chip8 {
    mem: Vec<u8>,
    reg_v: Vec<u8>,
    reg_i: u16,
    reg_delay_timer: Arc<AtomicUsize>,
    reg_sound_timer: u8,
    pc: usize,
    sp: usize,
    stack: Vec<usize>,
}

impl Chip8 {
    pub fn new(rom: &Vec<u8>) -> Chip8 {
        let mut chip8 = Chip8 {
            mem: vec![0; 0xFFF],
            reg_v: vec![0; 16],
            reg_i: 0,
            reg_delay_timer: Arc::new(AtomicUsize::new(0)),
            reg_sound_timer: 0,
            pc: 0x200,
            sp: 0,
            stack: vec![0; 16],
        };
        chip8.load_fonts();
        chip8.load_rom(rom);
        chip8
    }

    fn load_fonts(&mut self) {
        for i in FONT_BASE_ADDR..FONT_MAP.len() {
            self.mem[i] = FONT_MAP[i - FONT_BASE_ADDR]
        }
    }

    fn load_rom(&mut self, rom: &Vec<u8>) {
        for (b, buf_i) in rom.iter().enumerate() {
            self.mem[0x200 + b] = *buf_i;
        }
    }

    pub fn step(&mut self, peripherals: &mut Peripherals) {
        let hi_nibble = self.mem[self.pc] as u16;
        let lo_nibble = self.mem[self.pc + 1] as u16;
        let opcode = (hi_nibble << 8) | lo_nibble;
        match Instruction::try_from(opcode) {
            Err(msg) => panic!("Error decoding instruction at 0x{0:03x}: {1}", self.pc, msg),
            Ok(instruction) => self.step_instruction(instruction, peripherals),
        }
    }

    fn memory_read(&self, pos: usize) -> u8 {
        self.mem[pos]
    }

    fn memory_write(&mut self, pos: usize, data: u8) {
        self.mem[pos] = data;
        // println!("[W][0x{:03x}] 0x{:03x}", pos, data);
    }

    fn step_instruction(&mut self, instruction: Instruction, peripherals: &mut Peripherals) {
        match instruction {
            Instruction::Cls => peripherals.video_engine.cls(),
            Instruction::Ret => {
                assert!(self.sp > 0);
                self.sp -= 1;
                let old_pc = self.stack[self.sp];
                println!("Resuming execution at PC 0x{:x}", old_pc);
                self.pc = old_pc; // Jump to the instruction immediately after
            }
            Instruction::Jmp { addr } => self.pc = addr - 2, // Correct for pc increment later
            Instruction::Jsr { addr } => {
                self.stack[self.sp] = self.pc;
                self.sp += 1;
                self.pc = addr - 2
            } // Correct for pc increment later
            Instruction::Mov { vr, k } => self.reg_v[vr] = k,
            Instruction::Movr { vr, vy } => self.reg_v[vr] = self.reg_v[vy],
            Instruction::And { vr, vy } => self.reg_v[vr] &= self.reg_v[vy],
            Instruction::Shr { vr } => {
                let current_val = self.reg_v[vr];
                self.reg_v[0xF] = current_val & 1;
                self.reg_v[vr] = current_val >> 1;
            }
            Instruction::Skner { vr, vy } => {
                if self.reg_v[vr] != self.reg_v[vy] {
                    self.pc += 2;
                }
            }
            Instruction::Skeq { vr, k } => {
                if self.reg_v[vr] == k {
                    self.pc += 2
                }
            }
            Instruction::Skne { vr, k } => {
                if self.reg_v[vr] != k {
                    self.pc += 2
                }
            }
            Instruction::Add { vr, k } => {
                let old_val = self.reg_v[vr];
                self.reg_v[vr] = old_val.wrapping_add(k);
            }
            Instruction::Addr { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_r.overflowing_add(old_y);
                if overflow {
                    self.reg_v[0xF] = 1
                } else {
                    self.reg_v[0xF] = 0
                }
                self.reg_v[vr] = result;
            }
            Instruction::Mvi { k } => self.reg_i = k,
            Instruction::Rnd { vr, k } => {
                let mut buffer = [0u8; 1];
                thread_rng().fill_bytes(&mut buffer);
                self.reg_v[vr] = buffer[0] & k;
            }
            Instruction::Sprite { rx, ry, s } => {
                let x = self.reg_v[rx] as usize;
                let y = self.reg_v[ry] as usize;
                let height = s;
                self.reg_v[0xF] = 0;
                for yline in 0..height {
                    let mem_pos = self.reg_i as usize + yline as usize;
                    let pixel = self.memory_read(mem_pos);
                    for xline in 0..8 {
                        if pixel & (0x80 >> xline) != 0 {
                            let collision = peripherals.video_engine
                                .set_pixel_to_1(x + xline, y + yline);
                            if collision {
                                self.reg_v[0xF] = 1;
                            }
                        }

                    }
                }
            }
            Instruction::Skp { k } => {
                println!("Skipping if key {:x} is pressed", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => self.pc += 2,
                    _ => {}
                }
            }
            Instruction::Sknp { k } => {
                println!("Skipping if key {:x} is not pressed", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => {}
                    _ => self.pc += 2,
                }
            }
            Instruction::Key { vr } => {
                println!("Waiting for a key to be pressed");
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) => {
                        println!(" ... Got {:x}", x);
                        self.reg_v[vr] = x
                    }
                    _ => {
                        println!(" ... Waiting more");
                        self.pc -= 2; // Emulate a SLEEP
                    }
                }

            }
            Instruction::Adi { vr } => {
                self.reg_i += self.reg_v[vr] as u16;
            }
            Instruction::Font { vr } => {
                let character = self.reg_v[vr] as usize;
                self.reg_i = (FONT_BASE_ADDR + (character * FONT_SIZE)) as u16;
                println!("Font draw for character: {:x}", character);
            }
            Instruction::Bcd { vr } => {
                let value = self.reg_v[vr];
                let i = self.reg_i as usize;
                self.mem[i] = value / 100;
                self.mem[i + 1] = (value / 10) % 10;
                self.mem[i + 2] = value % 10;
            }
            Instruction::Str { vr } => {
                for idx in 0..(vr + 1) {
                    let target_pos = self.reg_i as usize + idx;
                    let data = self.reg_v[idx];
                    self.memory_write(target_pos, data);
                }
            }
            Instruction::Ldr { vr } => {
                for idx in 0..(vr + 1) {
                    self.reg_v[idx] = self.memory_read(self.reg_i as usize + idx)
                }
            }
            Instruction::Gdelay { vr } => {
                let amount = self.reg_delay_timer();
                self.reg_v[vr] = amount;
            }
            Instruction::Sdelay { vr } => {
                let amount = self.reg_v[vr];
                self.reg_delay_timer.store((amount + 1) as _, Ordering::SeqCst);
                let timer_clone = self.reg_delay_timer.clone();
                thread::spawn(move || loop {
                    let ticks_left = timer_clone.fetch_sub(1, Ordering::SeqCst) - 1;
                    if ticks_left > 0 {
                        println!("Still {} ticks left", ticks_left);
                        thread::sleep(time::Duration::from_millis(1000 / 60));
                    } else {
                        break;
                    }
                });
            }
        }
        self.pc += 2;
    }

    pub fn pc(&self) -> usize {
        self.pc
    }

    pub fn mem(&self) -> &Vec<u8> {
        &self.mem
    }

    pub fn reg_v(&self) -> &Vec<u8> {
        &self.reg_v
    }

    pub fn reg_i(&self) -> u16 {
        self.reg_i
    }

    pub fn reg_delay_timer(&self) -> u8 {
        self.reg_delay_timer.load(Ordering::SeqCst) as _
    }

    pub fn reg_sound_timer(&self) -> u8 {
        self.reg_sound_timer
    }

    pub fn stack(&self) -> &Vec<usize> {
        &self.stack
    }

    pub fn sp(&self) -> usize {
        self.sp
    }
}
<|endoftext|>