<commit_before>//! This module provides the logic necessary to implement a license prompt into
//! the hab CLI. When a user runs hab for the first time, they will be prompted
//! to accept the Chef license agreement. If they choose not to, then hab will
//! exit and they will be unable to use the tool.
//!
//! Choosing to accept the license will write a file to either
//! /hab/accepted-licenses/habitat (if run as root) or
//! ~/.hab/accepted-licenses/habitat. The presence of this file will
//! prevent further license prompts. The file itself contains various metadata
//! that we collect, but it's important to note that the contents of this file
//! are not strictly important. The important thing is the presence of the file.
//!
//! If a user was to read our code and pre-emptively create one of the above
//! files and leave its contents completely empty, that is sufficient for the
//! acceptance of the license. We will not overwrite their empty file, nor
//! will we care that it is empty.
//!
//! Because of this, the metadata that we store is not strictly necessary and
//! is more of a best effort scenario. If we can't collect all of it for
//! whatever reason, it's fine.
//!
//! Additionally, there are 2 environment variables that are supported to
//! constitute license acceptance. Setting HAB_LICENSE to "accept" will
//! accept the license and persist the file and setting HAB_LICENSE to
//! "accept-no-persist" will accept the license but not persist the
//! acceptance.
//!
//! More detailed information on the license spec is available at
//! https://github.com/chef/license-acceptance

use crate::{common::ui::{self,
                         UIReader,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            hcore::{fs::{am_i_root,
                         FS_ROOT_PATH},
                    users::get_current_username}};
use chrono::{DateTime,
             Utc};
use std::{env,
          fs::{self,
               File},
          io::Write,
          path::PathBuf};

const LICENSE_FILE_FORMAT_VERSION: &str = "1.0";
const LICENSE_ACCEPT_ENVVAR: &str = "HAB_LICENSE";

#[derive(Debug, Serialize, Deserialize)]
pub struct LicenseData {
    pub date_accepted: DateTime<Utc>,
    pub accepting_product: String,
    pub accepting_product_version: String,
    pub user: Option<String>,
    pub file_format: String,
}

impl LicenseData {
    pub fn new() -> Self {
        LicenseData { date_accepted: Utc::now(),
                      accepting_product: String::from("hab"),
                      accepting_product_version: super::VERSION.to_string(),
                      user: get_current_username(),
                      file_format: String::from(LICENSE_FILE_FORMAT_VERSION), }
    }
}

pub fn check_for_license_acceptance() -> Result<bool> {
    if license_exists() || env_var_present()? {
        return Ok(true);
    }

    Ok(false)
}

pub fn check_for_license_acceptance_and_prompt(ui: &mut UI) -> Result<()> {
    if check_for_license_acceptance()? {
        return Ok(());
    }

    ui.heading("+---------------------------------------------+")?;
    ui.heading("            Chef License Acceptance")?;
    ui.br()?;
    ui.info("Before you can continue, 1 product license must be accepted.")?;
    ui.info("View the license at https://www.chef.io/end-user-license-agreement")?;
    ui.br()?;
    ui.info("License that needs accepting:")?;
    ui.br()?;
    ui.info("  * Habitat")?;
    ui.br()?;

    if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
        accept_license(ui)
    } else {
        ui.br()?;
        ui.info("If you do not accept this license you will not be able to use Chef products.")?;
        ui.br()?;

        if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
            accept_license(ui)
        } else {
            ui.br()?;
            ui.heading("+---------------------------------------------+")?;
            Err(Error::LicenseNotAccepted)
        }
    }
}

pub fn accept_license(ui: &mut UI) -> Result<()> {
    if license_exists() {
        ui.info("You have already accepted the license.")?;
        return Ok(());
    }

    ui.br()?;
    ui.info("Accepting 1 product license...")?;

    write_license_file()?;

    ui.status(ui::Status::Custom(ui::Glyph::CheckMark, String::from("")),
              "1 product license accepted.")?;
    ui.br()?;
    ui.heading("+---------------------------------------------+")?;

    Ok(())
}

fn superuser_license_root() -> PathBuf { PathBuf::from(&*FS_ROOT_PATH).join("hab") }

fn user_license_root() -> PathBuf {
    if let Some(home) = dirs::home_dir() {
        home.join(".hab")
    } else {
        panic!("No home directory available. Unable to find a suitable place to write a license \
                file.");
    }
}

fn license_path(root_path: &PathBuf) -> PathBuf { root_path.join("accepted-licenses") }

fn license_file(license_path: &PathBuf) -> PathBuf { license_path.join("habitat") }

fn writeable_license_path() -> PathBuf {
    let root_dir = if am_i_root() {
        superuser_license_root()
    } else {
        user_license_root()
    };

    license_path(&root_dir)
}

fn env_var_present() -> Result<bool> {
    match env::var(LICENSE_ACCEPT_ENVVAR) {
        Ok(val) => {
            if &val == "accept" {
                write_license_file()?;
                Ok(true)
            } else if &val == "accept-no-persist" {
                Ok(true)
            } else {
                Ok(false)
            }
        }
        Err(_) => Ok(false),
    }
}

fn write_license_file() -> Result<()> {
    let license = LicenseData::new();
    let content = serde_yaml::to_string(&license)?;
    fs::create_dir_all(writeable_license_path())?;
    let mut file = File::create(license_file(&writeable_license_path()))?;
    file.write_all(content.as_bytes())?;
    Ok(())
}

pub fn license_exists() -> bool {
    license_file(&license_path(&user_license_root())).is_file()
    || license_file(&license_path(&superuser_license_root())).is_file()
}
<commit_msg>fallback to superuser root if home path cannot be found during license search<commit_after>//! This module provides the logic necessary to implement a license prompt into
//! the hab CLI. When a user runs hab for the first time, they will be prompted
//! to accept the Chef license agreement. If they choose not to, then hab will
//! exit and they will be unable to use the tool.
//!
//! Choosing to accept the license will write a file to either
//! /hab/accepted-licenses/habitat (if run as root) or
//! ~/.hab/accepted-licenses/habitat. The presence of this file will
//! prevent further license prompts. The file itself contains various metadata
//! that we collect, but it's important to note that the contents of this file
//! are not strictly important. The important thing is the presence of the file.
//!
//! If a user was to read our code and pre-emptively create one of the above
//! files and leave its contents completely empty, that is sufficient for the
//! acceptance of the license. We will not overwrite their empty file, nor
//! will we care that it is empty.
//!
//! Because of this, the metadata that we store is not strictly necessary and
//! is more of a best effort scenario. If we can't collect all of it for
//! whatever reason, it's fine.
//!
//! Additionally, there are 2 environment variables that are supported to
//! constitute license acceptance. Setting HAB_LICENSE to "accept" will
//! accept the license and persist the file and setting HAB_LICENSE to
//! "accept-no-persist" will accept the license but not persist the
//! acceptance.
//!
//! More detailed information on the license spec is available at
//! https://github.com/chef/license-acceptance

use crate::{common::ui::{self,
                         UIReader,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            hcore::{fs::{am_i_root,
                         FS_ROOT_PATH},
                    users::get_current_username}};
use chrono::{DateTime,
             Utc};
use std::{env,
          fs::{self,
               File},
          io::Write,
          path::PathBuf};

const LICENSE_FILE_FORMAT_VERSION: &str = "1.0";
const LICENSE_ACCEPT_ENVVAR: &str = "HAB_LICENSE";

#[derive(Debug, Serialize, Deserialize)]
pub struct LicenseData {
    pub date_accepted: DateTime<Utc>,
    pub accepting_product: String,
    pub accepting_product_version: String,
    pub user: Option<String>,
    pub file_format: String,
}

impl LicenseData {
    pub fn new() -> Self {
        LicenseData { date_accepted: Utc::now(),
                      accepting_product: String::from("hab"),
                      accepting_product_version: super::VERSION.to_string(),
                      user: get_current_username(),
                      file_format: String::from(LICENSE_FILE_FORMAT_VERSION), }
    }
}

pub fn check_for_license_acceptance() -> Result<bool> {
    if license_exists() || env_var_present()? {
        return Ok(true);
    }

    Ok(false)
}

pub fn check_for_license_acceptance_and_prompt(ui: &mut UI) -> Result<()> {
    if check_for_license_acceptance()? {
        return Ok(());
    }

    ui.heading("+---------------------------------------------+")?;
    ui.heading("            Chef License Acceptance")?;
    ui.br()?;
    ui.info("Before you can continue, 1 product license must be accepted.")?;
    ui.info("View the license at https://www.chef.io/end-user-license-agreement")?;
    ui.br()?;
    ui.info("License that needs accepting:")?;
    ui.br()?;
    ui.info("  * Habitat")?;
    ui.br()?;

    if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
        accept_license(ui)
    } else {
        ui.br()?;
        ui.info("If you do not accept this license you will not be able to use Chef products.")?;
        ui.br()?;

        if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
            accept_license(ui)
        } else {
            ui.br()?;
            ui.heading("+---------------------------------------------+")?;
            Err(Error::LicenseNotAccepted)
        }
    }
}

pub fn accept_license(ui: &mut UI) -> Result<()> {
    if license_exists() {
        ui.info("You have already accepted the license.")?;
        return Ok(());
    }

    ui.br()?;
    ui.info("Accepting 1 product license...")?;

    write_license_file()?;

    ui.status(ui::Status::Custom(ui::Glyph::CheckMark, String::from("")),
              "1 product license accepted.")?;
    ui.br()?;
    ui.heading("+---------------------------------------------+")?;

    Ok(())
}

fn superuser_license_root() -> PathBuf { PathBuf::from(&*FS_ROOT_PATH).join("hab") }

fn user_license_root() -> PathBuf {
    if let Some(home) = dirs::home_dir() {
        home.join(".hab")
    } else {
        superuser_license_root()
    }
}

fn license_path(root_path: &PathBuf) -> PathBuf { root_path.join("accepted-licenses") }

fn license_file(license_path: &PathBuf) -> PathBuf { license_path.join("habitat") }

fn writeable_license_path() -> PathBuf {
    let root_dir = if am_i_root() {
        superuser_license_root()
    } else {
        user_license_root()
    };

    license_path(&root_dir)
}

fn env_var_present() -> Result<bool> {
    match env::var(LICENSE_ACCEPT_ENVVAR) {
        Ok(val) => {
            if &val == "accept" {
                write_license_file()?;
                Ok(true)
            } else if &val == "accept-no-persist" {
                Ok(true)
            } else {
                Ok(false)
            }
        }
        Err(_) => Ok(false),
    }
}

fn write_license_file() -> Result<()> {
    let license = LicenseData::new();
    let content = serde_yaml::to_string(&license)?;
    fs::create_dir_all(writeable_license_path())?;
    let mut file = File::create(license_file(&writeable_license_path()))?;
    file.write_all(content.as_bytes())?;
    Ok(())
}

pub fn license_exists() -> bool {
    license_file(&license_path(&user_license_root())).is_file()
    || license_file(&license_path(&superuser_license_root())).is_file()
}
<|endoftext|>


<commit_before>use std::fmt;

use crate::mir;
use crate::ty::layout::{self, HasDataLayout, Size};
use rustc_macros::HashStable;

use super::{
    AllocId, EvalResult, InboundsCheck,
};

////////////////////////////////////////////////////////////////////////////////
// Pointer arithmetic
////////////////////////////////////////////////////////////////////////////////

pub trait PointerArithmetic: layout::HasDataLayout {
    // These are not supposed to be overridden.

    #[inline(always)]
    fn pointer_size(&self) -> Size {
        self.data_layout().pointer_size
    }

    //// Trunace the given value to the pointer size; also return whether there was an overflow
    #[inline]
    fn truncate_to_ptr(&self, val: u128) -> (u64, bool) {
        let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
        ((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
    }

    #[inline]
    fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
        let (res, over) = self.overflowing_offset(val, i);
        if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
    }

    #[inline]
    fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
        let (res, over1) = val.overflowing_add(i);
        let (res, over2) = self.truncate_to_ptr(u128::from(res));
        (res, over1 || over2)
    }

    #[inline]
    fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
        let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
        if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
    }

    // Overflow checking only works properly on the range from -u64 to +u64.
    #[inline]
    fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
        // FIXME: is it possible to over/underflow here?
        if i < 0 {
            // trickery to ensure that i64::min_value() works fine
            // this formula only works for true negative values, it panics for zero!
            let n = u64::max_value() - (i as u64) + 1;
            val.overflowing_sub(n)
        } else {
            self.overflowing_offset(val, i as u64)
        }
    }
}

impl<T: layout::HasDataLayout> PointerArithmetic for T {}

/// Pointer is generic over the type that represents a reference to Allocations,
/// thus making it possible for the most convenient representation to be used in
/// each context.
///
/// Defaults to the index based and loosely coupled AllocId.
///
/// Pointer is also generic over the `Tag` associated with each pointer,
/// which is used to do provenance tracking during execution.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
         RustcEncodable, RustcDecodable, Hash, HashStable)]
pub struct Pointer<Tag=(),Id=AllocId> {
    pub alloc_id: Id,
    pub offset: Size,
    pub tag: Tag,
}

static_assert_size!(Pointer, 16);

impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for Pointer<Tag, Id> {
    default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}.{:#x}[{:?}]", self.alloc_id, self.offset.bytes(), self.tag)
    }
}
// Specialization for no tag
impl<Id: fmt::Debug> fmt::Debug for Pointer<(), Id> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}.{:#x}", self.alloc_id, self.offset.bytes())
    }
}

/// Produces a `Pointer` which points to the beginning of the Allocation
impl From<AllocId> for Pointer {
    #[inline(always)]
    fn from(alloc_id: AllocId) -> Self {
        Pointer::new(alloc_id, Size::ZERO)
    }
}

impl<'tcx> Pointer<()> {
    #[inline(always)]
    pub fn new(alloc_id: AllocId, offset: Size) -> Self {
        Pointer { alloc_id, offset, tag: () }
    }

    #[inline(always)]
    pub fn with_tag<Tag>(self, tag: Tag) -> Pointer<Tag>
    {
        Pointer::new_with_tag(self.alloc_id, self.offset, tag)
    }

    #[inline(always)]
    pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
        where Tag: Default
    {
        self.with_tag(Tag::default())
    }
}

impl<'tcx, Tag> Pointer<Tag> {
    #[inline(always)]
    pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
        Pointer { alloc_id, offset, tag }
    }

    #[inline]
    pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
        Ok(Pointer::new_with_tag(
            self.alloc_id,
            Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
            self.tag
        ))
    }

    #[inline]
    pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
        (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
    }

    #[inline(always)]
    pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
        self.overflowing_offset(i, cx).0
    }

    #[inline]
    pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
        Ok(Pointer::new_with_tag(
            self.alloc_id,
            Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
            self.tag,
        ))
    }

    #[inline]
    pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
        (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
    }

    #[inline(always)]
    pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
        self.overflowing_signed_offset(i128::from(i), cx).0
    }

    #[inline(always)]
    pub fn erase_tag(self) -> Pointer {
        Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
    }

    #[inline(always)]
    pub fn check_in_alloc(
        self,
        allocation_size: Size,
        check: InboundsCheck,
    ) -> EvalResult<'tcx, ()> {
        if self.offset > allocation_size {
            err!(PointerOutOfBounds {
                ptr: self.erase_tag(),
                check,
                allocation_size,
            })
        } else {
            Ok(())
        }
    }
}
<commit_msg>fix overflow error in signed wrapping offset<commit_after>use std::fmt;

use crate::mir;
use crate::ty::layout::{self, HasDataLayout, Size};
use rustc_macros::HashStable;

use super::{
    AllocId, EvalResult, InboundsCheck,
};

////////////////////////////////////////////////////////////////////////////////
// Pointer arithmetic
////////////////////////////////////////////////////////////////////////////////

pub trait PointerArithmetic: layout::HasDataLayout {
    // These are not supposed to be overridden.

    #[inline(always)]
    fn pointer_size(&self) -> Size {
        self.data_layout().pointer_size
    }

    /// Helper function: truncate given value-"overflowed flag" pair to pointer size and
    /// update "overflowed flag" if there was an overflow.
    /// This should be called by all the other methods before returning!
    #[inline]
    fn truncate_to_ptr(&self, (val, over): (u64, bool)) -> (u64, bool) {
        let val = val as u128;
        let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
        ((val % max_ptr_plus_1) as u64, over || val >= max_ptr_plus_1)
    }

    #[inline]
    fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
        let res = val.overflowing_add(i);
        self.truncate_to_ptr(res)
    }

    // Overflow checking only works properly on the range from -u64 to +u64.
    #[inline]
    fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
        // FIXME: is it possible to over/underflow here?
        if i < 0 {
            // Trickery to ensure that i64::min_value() works fine: compute n = -i.
            // This formula only works for true negative values, it overflows for zero!
            let n = u64::max_value() - (i as u64) + 1;
            let res = val.overflowing_sub(n);
            self.truncate_to_ptr(res)
        } else {
            self.overflowing_offset(val, i as u64)
        }
    }

    #[inline]
    fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
        let (res, over) = self.overflowing_offset(val, i);
        if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
    }

    #[inline]
    fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
        let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
        if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
    }
}

impl<T: layout::HasDataLayout> PointerArithmetic for T {}

/// Pointer is generic over the type that represents a reference to Allocations,
/// thus making it possible for the most convenient representation to be used in
/// each context.
///
/// Defaults to the index based and loosely coupled AllocId.
///
/// Pointer is also generic over the `Tag` associated with each pointer,
/// which is used to do provenance tracking during execution.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
         RustcEncodable, RustcDecodable, Hash, HashStable)]
pub struct Pointer<Tag=(),Id=AllocId> {
    pub alloc_id: Id,
    pub offset: Size,
    pub tag: Tag,
}

static_assert_size!(Pointer, 16);

impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for Pointer<Tag, Id> {
    default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}.{:#x}[{:?}]", self.alloc_id, self.offset.bytes(), self.tag)
    }
}
// Specialization for no tag
impl<Id: fmt::Debug> fmt::Debug for Pointer<(), Id> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}.{:#x}", self.alloc_id, self.offset.bytes())
    }
}

/// Produces a `Pointer` which points to the beginning of the Allocation
impl From<AllocId> for Pointer {
    #[inline(always)]
    fn from(alloc_id: AllocId) -> Self {
        Pointer::new(alloc_id, Size::ZERO)
    }
}

impl<'tcx> Pointer<()> {
    #[inline(always)]
    pub fn new(alloc_id: AllocId, offset: Size) -> Self {
        Pointer { alloc_id, offset, tag: () }
    }

    #[inline(always)]
    pub fn with_tag<Tag>(self, tag: Tag) -> Pointer<Tag>
    {
        Pointer::new_with_tag(self.alloc_id, self.offset, tag)
    }

    #[inline(always)]
    pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
        where Tag: Default
    {
        self.with_tag(Tag::default())
    }
}

impl<'tcx, Tag> Pointer<Tag> {
    #[inline(always)]
    pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
        Pointer { alloc_id, offset, tag }
    }

    #[inline]
    pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
        Ok(Pointer::new_with_tag(
            self.alloc_id,
            Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
            self.tag
        ))
    }

    #[inline]
    pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
        (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
    }

    #[inline(always)]
    pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
        self.overflowing_offset(i, cx).0
    }

    #[inline]
    pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
        Ok(Pointer::new_with_tag(
            self.alloc_id,
            Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
            self.tag,
        ))
    }

    #[inline]
    pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
        (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
    }

    #[inline(always)]
    pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
        self.overflowing_signed_offset(i128::from(i), cx).0
    }

    #[inline(always)]
    pub fn erase_tag(self) -> Pointer {
        Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
    }

    #[inline(always)]
    pub fn check_in_alloc(
        self,
        allocation_size: Size,
        check: InboundsCheck,
    ) -> EvalResult<'tcx, ()> {
        if self.offset > allocation_size {
            err!(PointerOutOfBounds {
                ptr: self.erase_tag(),
                check,
                allocation_size,
            })
        } else {
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate file;
extern crate fall_gen;
extern crate lang_fall;
extern crate fall_tree;

use std::error::Error;
use std::io::Write;
use std::path::{PathBuf, Path};
use std::fs;
use std::process::{Command, Stdio};

use clap::{App, Arg};

enum Task {
    Generate(PathBuf),
    Examples(PathBuf)
}

fn main() {
    let matches = App::new("Fall parser generator")
        .arg(Arg::with_name("grammar").index(1).required(true))
        .arg(Arg::with_name("examples").long("examples"))
        .get_matches();
    let grammar = PathBuf::from(matches.value_of("grammar").unwrap());
    let command = if matches.is_present("examples") {
        Task::Examples(grammar)
    } else {
        Task::Generate(grammar)
    };

    let return_code = if let Err(e) = main_inner(command) {
        writeln!(::std::io::stderr(), "Error occurred: {}", e).unwrap();
        101
    } else {
        0
    };
    std::process::exit(return_code)
}

fn main_inner(command: Task) -> Result<(), Box<Error>> {
    match command {
        Task::Generate(grammar) => {
            let input = file::get_text(&grammar)?;
            let file = lang_fall::LANG_FALL.parse(input);
            let ast = lang_fall::ast(&file);
            let result = fall_gen::generate(ast)?;
            file::put_text(grammar.with_extension("rs"), result)?;
        }
        Task::Examples(grammar) => {
            let input = file::get_text(&grammar)?;
            let result = render_examples(input)?;
            file::put_text(grammar.with_extension("txt"), result)?;
        }
    }
    Ok(())
}

fn render_examples(grammar: String) -> Result<String, Box<Error>> {
    let file = lang_fall::LANG_FALL.parse(grammar);
    let ast = lang_fall::ast(&file);
    let parser = fall_gen::generate(ast)?;
    let example = match ast.examples().next() {
        Some(ex) => ex.contents().to_string(),
        None => return Ok("".to_owned())
    };

    let base_dir = base_directory()?;
    let syntax = base_dir.join("src").join("syntax.rs");
    put_text_if_changed(&syntax, &parser)?;
    let toml = base_dir.join("Cargo.toml");
    put_text_if_changed(&toml, &format!(r##"
        [package]
        name = "fall_examples"
        version = "0.1.0"
        authors = []

        [workspace]

        [dependencies]
        regex = "0.2"
        serde_json = "1.*"
        lazy_static = "0.2"

        fall_tree = {{ path = "{fall_dir}/fall_tree" }}
        fall_parse = {{ path = "{fall_dir}/fall_parse" }}
    "##, fall_dir = fall_dir().display()))?;
    put_text_if_changed(&base_dir.join("src").join("main.rs"), r##"
        #![allow(warnings)]
        extern crate regex;
        extern crate fall_tree;
        extern crate fall_parse;
        #[macro_use]
        extern crate lazy_static;
        extern crate serde_json;
        mod syntax;

        use std::io::Read;

        fn main() {
            let mut input = String::new();
            ::std::io::stdin().read_to_string(&mut input).unwrap();
            let file = syntax::LANG.parse(input);
            println!("{}", fall_tree::dump_file(&file));
        }
    "##)?;

    let build = Command::new("cargo")
        .arg("build")
        .arg("--manifest-path")
        .arg(&toml)
        .spawn()?
        .wait_with_output()?;

    if !build.status.success() {
        return Ok(String::from_utf8(build.stderr).unwrap());
    }

    let mut child = Command::new("cargo")
        .arg("run")
        .arg("--manifest-path")
        .arg(&toml)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;

    {
        let mut stdin = child.stdin.as_mut().unwrap();
        stdin.write_all(example.as_bytes()).unwrap();
        stdin.flush().unwrap();
    }

    let rendered = child.wait_with_output()?;
    assert!(rendered.status.success());
    let out = String::from_utf8(rendered.stdout).unwrap();
    Ok(out)
}

fn base_directory() -> Result<PathBuf, Box<Error>> {
    let result = ::std::env::temp_dir().join("fall-examples");
    fs::create_dir_all(&result)?;
    fs::create_dir_all(&result.join("src"))?;
    Ok(result)
}

fn fall_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir).parent().unwrap().to_owned()
}

fn put_text_if_changed(path: &Path, text: &str) -> ::std::io::Result<()> {
    if path.exists() {
        let old_text = file::get_text(path)?;
        if old_text == text {
            return Ok(())
        }
    }
    file::put_text(path, text)
}
<commit_msg>Don't swallow errors<commit_after>extern crate clap;
extern crate file;
extern crate fall_gen;
extern crate lang_fall;
extern crate fall_tree;

use std::error::Error;
use std::io::Write;
use std::path::{PathBuf, Path};
use std::fs;
use std::process::{Command, Stdio};

use clap::{App, Arg};

enum Task {
    Generate(PathBuf),
    Examples(PathBuf)
}

fn main() {
    let matches = App::new("Fall parser generator")
        .arg(Arg::with_name("grammar").index(1).required(true))
        .arg(Arg::with_name("examples").long("examples"))
        .get_matches();
    let grammar = PathBuf::from(matches.value_of("grammar").unwrap());
    let command = if matches.is_present("examples") {
        Task::Examples(grammar)
    } else {
        Task::Generate(grammar)
    };

    let return_code = if let Err(e) = main_inner(command) {
        writeln!(::std::io::stderr(), "Error occurred: {}", e).unwrap();
        101
    } else {
        0
    };
    std::process::exit(return_code)
}

fn main_inner(command: Task) -> Result<(), Box<Error>> {
    match command {
        Task::Generate(grammar) => {
            let input = file::get_text(&grammar)?;
            let file = lang_fall::LANG_FALL.parse(input);
            let ast = lang_fall::ast(&file);
            let result = fall_gen::generate(ast)?;
            file::put_text(grammar.with_extension("rs"), result)?;
        }
        Task::Examples(grammar) => {
            let input = file::get_text(&grammar)?;
            let result = render_examples(input)?;
            file::put_text(grammar.with_extension("txt"), result)?;
        }
    }
    Ok(())
}

fn render_examples(grammar: String) -> Result<String, Box<Error>> {
    let file = lang_fall::LANG_FALL.parse(grammar);
    let ast = lang_fall::ast(&file);
    let parser = match fall_gen::generate(ast) {
        Ok(parser) => parser,
        Err(e) => return Ok(format!("error:\n{}", e))
    };
    let example = match ast.examples().next() {
        Some(ex) => ex.contents().to_string(),
        None => return Ok("".to_owned())
    };

    let base_dir = base_directory()?;
    let syntax = base_dir.join("src").join("syntax.rs");
    put_text_if_changed(&syntax, &parser)?;
    let toml = base_dir.join("Cargo.toml");
    put_text_if_changed(&toml, &format!(r##"
        [package]
        name = "fall_examples"
        version = "0.1.0"
        authors = []

        [workspace]

        [dependencies]
        regex = "0.2"
        serde_json = "1.*"
        lazy_static = "0.2"

        fall_tree = {{ path = "{fall_dir}/fall_tree" }}
        fall_parse = {{ path = "{fall_dir}/fall_parse" }}
    "##, fall_dir = fall_dir().display()))?;
    put_text_if_changed(&base_dir.join("src").join("main.rs"), r##"
        #![allow(warnings)]
        extern crate regex;
        extern crate fall_tree;
        extern crate fall_parse;
        #[macro_use]
        extern crate lazy_static;
        extern crate serde_json;
        mod syntax;

        use std::io::Read;

        fn main() {
            let mut input = String::new();
            ::std::io::stdin().read_to_string(&mut input).unwrap();
            let file = syntax::LANG.parse(input);
            println!("{}", fall_tree::dump_file(&file));
        }
    "##)?;

    let build = Command::new("cargo")
        .arg("build")
        .arg("--manifest-path")
        .arg(&toml)
        .spawn()?
        .wait_with_output()?;

    if !build.status.success() {
        return Ok(String::from_utf8(build.stderr).unwrap());
    }

    let mut child = Command::new("cargo")
        .arg("run")
        .arg("--manifest-path")
        .arg(&toml)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;

    {
        let mut stdin = child.stdin.as_mut().unwrap();
        stdin.write_all(example.as_bytes()).unwrap();
        stdin.flush().unwrap();
    }

    let rendered = child.wait_with_output()?;
    assert!(rendered.status.success());
    let mut result = String::new();
    if !rendered.stderr.is_empty() {
        result += &::std::str::from_utf8(&rendered.stderr).unwrap();
        result += "\n\n";
    }
    result += &::std::str::from_utf8(&rendered.stdout).unwrap();
    Ok(result)
}

fn base_directory() -> Result<PathBuf, Box<Error>> {
    let result = ::std::env::temp_dir().join("fall-examples");
    fs::create_dir_all(&result)?;
    fs::create_dir_all(&result.join("src"))?;
    Ok(result)
}

fn fall_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir).parent().unwrap().to_owned()
}

fn put_text_if_changed(path: &Path, text: &str) -> ::std::io::Result<()> {
    if path.exists() {
        let old_text = file::get_text(path)?;
        if old_text == text {
            return Ok(())
        }
    }
    file::put_text(path, text)
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

#[macro_use] extern crate log;
extern crate clap;
extern crate semver;
extern crate toml;
extern crate url;
#[macro_use] extern crate version;

extern crate libimagentrylink;
extern crate libimagrt;
extern crate libimagstore;
extern crate libimagerror;
extern crate libimagutil;

use std::ops::Deref;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagstore::error::StoreError;
use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};
use libimagentrylink::external::ExternalLinker;
use libimagutil::warn_result::*;
use libimagutil::warn_exit::warn_exit;
use libimagutil::info_result::*;
use clap::ArgMatches;
use url::Url;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-link",
                                    &version!()[..],
                                    "Link entries",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            match name {
                "internal" => handle_internal_linking(&rt),
                "external" => handle_external_linking(&rt),
                _ => warn_exit("No commandline call", 1)
            }
        });
}

fn handle_internal_linking(rt: &Runtime) {
    use libimagentrylink::internal::InternalLinker;
    use libimagentrylink::external::is_external_link_storeid;

    debug!("Handle internal linking call");
    let cmd = rt.cli().subcommand_matches("internal").unwrap();

    match cmd.value_of("list") {
        Some(list) => {
            debug!("List...");
            for entry in list.split(',') {
                debug!("Listing for '{}'", entry);
                match get_entry_by_name(rt, entry) {
                    Ok(Some(e)) => {
                        e.get_internal_links()
                            .map(|iter| {
                                iter.filter(move |id| {
                                    cmd.is_present("list-externals-too") || !is_external_link_storeid(&id)
                                })
                            })
                            .map(|links| {
                                let i = links
                                    .filter_map(|l| {
                                        l.to_str()
                                            .map_warn_err(|e| format!("Failed to convert StoreId to string: {:?}", e))
                                            .ok()
                                    })
                                    .enumerate();

                                for (i, link) in i {
                                    println!("{: <3}: {}", i, link);
                                }
                            })
                            .map_err_trace()
                            .ok();
                    },

                    Ok(None) => {
                        warn!("Entry not found: {:?}", entry);
                        break;
                    }

                    Err(e) => {
                        trace_error(&e);
                        break;
                    },
                }
            }
            debug!("Listing ready!");
        },
        None => {
            match cmd.subcommand_name() {
                Some("add") => {
                    let (mut from, to) = get_from_to_entry(&rt, "add");
                    for mut to_entry in to {
                        if let Err(e) = to_entry.add_internal_link(&mut from) {
                            trace_error_exit(&e, 1);
                        }
                    }
                },

                Some("remove") => {
                    let (mut from, to) = get_from_to_entry(&rt, "remove");
                    for mut to_entry in to {
                        if let Err(e) = to_entry.remove_internal_link(&mut from) {
                            trace_error_exit(&e, 1);
                        }
                    }
                },

                _ => unreachable!(),
            };
        }
    }
}

fn get_from_to_entry<'a>(rt: &'a Runtime, subcommand: &str) -> (FileLockEntry<'a>, Vec<FileLockEntry<'a>>) {
    let from = match get_from_entry(&rt, subcommand) {
        None => warn_exit("No 'from' entry", 1),
        Some(s) => s,
    };
    debug!("Link from = {:?}", from.deref());

    let to = match get_to_entries(&rt, subcommand) {
        None => warn_exit("No 'to' entry", 1),
        Some(to) => to,
    };
    debug!("Link to = {:?}", to.iter().map(|f| f.deref()).collect::<Vec<&Entry>>());

    (from, to)
}

fn get_from_entry<'a>(rt: &'a Runtime, subcommand: &str) -> Option<FileLockEntry<'a>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches(subcommand)
        .unwrap() // safe, we know there is an "add" subcommand
        .value_of("from")
        .and_then(|from_name| {
            match get_entry_by_name(rt, from_name) {
                Err(e) => {
                    debug!("We couldn't get the entry from name: '{:?}'", from_name);
                    trace_error(&e); None
                },
                Ok(Some(e)) => Some(e),
                Ok(None)    => None,
            }

        })
}

fn get_to_entries<'a>(rt: &'a Runtime, subcommand: &str) -> Option<Vec<FileLockEntry<'a>>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches(subcommand)
        .unwrap() // safe, we know there is an "add" subcommand
        .values_of("to")
        .map(|values| {
            let mut v = vec![];
            for entry in values.map(|v| get_entry_by_name(rt, v)) {
                match entry {
                    Err(e) => trace_error(&e),
                    Ok(Some(e)) => v.push(e),
                    Ok(None) => warn!("Entry not found: {:?}", v),
                }
            }
            v
        })
}

fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockEntry<'a>>, StoreError> {
    use std::path::PathBuf;
    use libimagstore::storeid::StoreId;

    StoreId::new(Some(rt.store().path().clone()), PathBuf::from(name))
        .and_then(|id| rt.store().get(id))
}

fn handle_external_linking(rt: &Runtime) {
    let scmd       = rt.cli().subcommand_matches("external").unwrap();
    let entry_name = scmd.value_of("id").unwrap(); // enforced by clap
    let mut entry  = match get_entry_by_name(rt, entry_name) {
        Err(e) => trace_error_exit(&e, 1),
        Ok(None) => {
            warn!("Entry not found: {:?}", entry_name);
            return;
        },
        Ok(Some(entry)) => entry
    };

    if scmd.is_present("add") {
        debug!("Adding link to entry!");
        add_link_to_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("remove") {
        debug!("Removing link from entry!");
        remove_link_from_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("set") {
        debug!("Setting links in entry!");
        set_links_for_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("list") {
        debug!("Listing links in entry!");
        list_links_for_entry(rt.store(), &mut entry);
        return;
    }

    panic!("Clap failed to enforce one of 'add', 'remove', 'set' or 'list'");
}

fn add_link_to_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    Url::parse(matches.value_of("add").unwrap())
        .map_err_trace_exit(1)
        .map(|link| entry.add_external_link(store, link).map_err_trace().map_info_str("Ok"))
        .ok();
}

fn remove_link_from_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    Url::parse(matches.value_of("remove").unwrap())
        .map_err_trace_exit(1)
        .map(|link| entry.remove_external_link(store, link).map_err_trace().map_info_str("Ok"))
        .ok();
}

fn set_links_for_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let links = matches
        .value_of("links")
        .map(String::from)
        .unwrap()
        .split(',')
        .map(|uri| {
            match Url::parse(uri) {
                Err(e) => {
                    warn!("Could not parse '{}' as URL, ignoring", uri);
                    trace_error(&e);
                    None
                },
                Ok(u) => Some(u),
            }
        })
        .filter_map(|x| x)
        .collect();

    entry.set_external_links(store, links)
        .map_err_trace()
        .map_info_str("Ok")
        .ok();
}

fn list_links_for_entry(store: &Store, entry: &mut FileLockEntry) {
    entry.get_external_links(store)
        .and_then(|links| {
            for (i, link) in links.enumerate() {
                match link {
                    Ok(link) => println!("{: <3}: {}", i, link),
                    Err(e)   => trace_error(&e),
                }
            }
            Ok(())
        })
        .map_err_trace()
        .map_info_str("Ok")
        .ok();
}

<commit_msg>Extract internal linking list call handling<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

#[macro_use] extern crate log;
extern crate clap;
extern crate semver;
extern crate toml;
extern crate url;
#[macro_use] extern crate version;

extern crate libimagentrylink;
extern crate libimagrt;
extern crate libimagstore;
extern crate libimagerror;
extern crate libimagutil;

use std::ops::Deref;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagstore::error::StoreError;
use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};
use libimagentrylink::external::ExternalLinker;
use libimagentrylink::internal::InternalLinker;
use libimagutil::warn_result::*;
use libimagutil::warn_exit::warn_exit;
use libimagutil::info_result::*;
use clap::ArgMatches;
use url::Url;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-link",
                                    &version!()[..],
                                    "Link entries",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            match name {
                "internal" => handle_internal_linking(&rt),
                "external" => handle_external_linking(&rt),
                _ => warn_exit("No commandline call", 1)
            }
        });
}

fn handle_internal_linking(rt: &Runtime) {

    debug!("Handle internal linking call");
    let cmd = rt.cli().subcommand_matches("internal").unwrap();

    match cmd.value_of("list") {
        Some(list) => handle_internal_linking_list_call(rt, cmd, list),
        None => {
            match cmd.subcommand_name() {
                Some("add") => {
                    let (mut from, to) = get_from_to_entry(&rt, "add");
                    for mut to_entry in to {
                        if let Err(e) = to_entry.add_internal_link(&mut from) {
                            trace_error_exit(&e, 1);
                        }
                    }
                },

                Some("remove") => {
                    let (mut from, to) = get_from_to_entry(&rt, "remove");
                    for mut to_entry in to {
                        if let Err(e) = to_entry.remove_internal_link(&mut from) {
                            trace_error_exit(&e, 1);
                        }
                    }
                },

                _ => unreachable!(),
            };
        }
    }
}

#[inline]
fn handle_internal_linking_list_call(rt: &Runtime, cmd: &ArgMatches, list: &str) {
    use libimagentrylink::external::is_external_link_storeid;

    debug!("List...");
    for entry in list.split(',') {
        debug!("Listing for '{}'", entry);
        match get_entry_by_name(rt, entry) {
            Ok(Some(e)) => {
                e.get_internal_links()
                    .map(|iter| {
                        iter.filter(move |id| {
                            cmd.is_present("list-externals-too") || !is_external_link_storeid(&id)
                        })
                    })
                    .map(|links| {
                        let i = links
                            .filter_map(|l| {
                                l.to_str()
                                    .map_warn_err(|e| format!("Failed to convert StoreId to string: {:?}", e))
                                    .ok()
                            })
                            .enumerate();

                        for (i, link) in i {
                            println!("{: <3}: {}", i, link);
                        }
                    })
                    .map_err_trace()
                    .ok();
            },

            Ok(None) => {
                warn!("Entry not found: {:?}", entry);
                break;
            }

            Err(e) => {
                trace_error(&e);
                break;
            },
        }
    }
    debug!("Listing ready!");
}

fn get_from_to_entry<'a>(rt: &'a Runtime, subcommand: &str) -> (FileLockEntry<'a>, Vec<FileLockEntry<'a>>) {
    let from = match get_from_entry(&rt, subcommand) {
        None => warn_exit("No 'from' entry", 1),
        Some(s) => s,
    };
    debug!("Link from = {:?}", from.deref());

    let to = match get_to_entries(&rt, subcommand) {
        None => warn_exit("No 'to' entry", 1),
        Some(to) => to,
    };
    debug!("Link to = {:?}", to.iter().map(|f| f.deref()).collect::<Vec<&Entry>>());

    (from, to)
}

fn get_from_entry<'a>(rt: &'a Runtime, subcommand: &str) -> Option<FileLockEntry<'a>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches(subcommand)
        .unwrap() // safe, we know there is an "add" subcommand
        .value_of("from")
        .and_then(|from_name| {
            match get_entry_by_name(rt, from_name) {
                Err(e) => {
                    debug!("We couldn't get the entry from name: '{:?}'", from_name);
                    trace_error(&e); None
                },
                Ok(Some(e)) => Some(e),
                Ok(None)    => None,
            }

        })
}

fn get_to_entries<'a>(rt: &'a Runtime, subcommand: &str) -> Option<Vec<FileLockEntry<'a>>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches(subcommand)
        .unwrap() // safe, we know there is an "add" subcommand
        .values_of("to")
        .map(|values| {
            let mut v = vec![];
            for entry in values.map(|v| get_entry_by_name(rt, v)) {
                match entry {
                    Err(e) => trace_error(&e),
                    Ok(Some(e)) => v.push(e),
                    Ok(None) => warn!("Entry not found: {:?}", v),
                }
            }
            v
        })
}

fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockEntry<'a>>, StoreError> {
    use std::path::PathBuf;
    use libimagstore::storeid::StoreId;

    StoreId::new(Some(rt.store().path().clone()), PathBuf::from(name))
        .and_then(|id| rt.store().get(id))
}

fn handle_external_linking(rt: &Runtime) {
    let scmd       = rt.cli().subcommand_matches("external").unwrap();
    let entry_name = scmd.value_of("id").unwrap(); // enforced by clap
    let mut entry  = match get_entry_by_name(rt, entry_name) {
        Err(e) => trace_error_exit(&e, 1),
        Ok(None) => {
            warn!("Entry not found: {:?}", entry_name);
            return;
        },
        Ok(Some(entry)) => entry
    };

    if scmd.is_present("add") {
        debug!("Adding link to entry!");
        add_link_to_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("remove") {
        debug!("Removing link from entry!");
        remove_link_from_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("set") {
        debug!("Setting links in entry!");
        set_links_for_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("list") {
        debug!("Listing links in entry!");
        list_links_for_entry(rt.store(), &mut entry);
        return;
    }

    panic!("Clap failed to enforce one of 'add', 'remove', 'set' or 'list'");
}

fn add_link_to_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    Url::parse(matches.value_of("add").unwrap())
        .map_err_trace_exit(1)
        .map(|link| entry.add_external_link(store, link).map_err_trace().map_info_str("Ok"))
        .ok();
}

fn remove_link_from_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    Url::parse(matches.value_of("remove").unwrap())
        .map_err_trace_exit(1)
        .map(|link| entry.remove_external_link(store, link).map_err_trace().map_info_str("Ok"))
        .ok();
}

fn set_links_for_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let links = matches
        .value_of("links")
        .map(String::from)
        .unwrap()
        .split(',')
        .map(|uri| {
            match Url::parse(uri) {
                Err(e) => {
                    warn!("Could not parse '{}' as URL, ignoring", uri);
                    trace_error(&e);
                    None
                },
                Ok(u) => Some(u),
            }
        })
        .filter_map(|x| x)
        .collect();

    entry.set_external_links(store, links)
        .map_err_trace()
        .map_info_str("Ok")
        .ok();
}

fn list_links_for_entry(store: &Store, entry: &mut FileLockEntry) {
    entry.get_external_links(store)
        .and_then(|links| {
            for (i, link) in links.enumerate() {
                match link {
                    Ok(link) => println!("{: <3}: {}", i, link),
                    Err(e)   => trace_error(&e),
                }
            }
            Ok(())
        })
        .map_err_trace()
        .map_info_str("Ok")
        .ok();
}

<|endoftext|>


<commit_before>use super::BLOCKS_DB_COLUMN as DB_COLUMN;
use super::{ClientDB, DBError};
use ssz::Decodable;
use std::sync::Arc;
use types::{readers::BeaconBlockReader, BeaconBlock, Hash256};

#[derive(Clone, Debug, PartialEq)]
pub enum BeaconBlockAtSlotError {
    UnknownBeaconBlock(Hash256),
    InvalidBeaconBlock(Hash256),
    DBError(String),
}

pub struct BeaconBlockStore<T>
where
    T: ClientDB,
{
    db: Arc<T>,
}

// Implements `put`, `get`, `exists` and `delete` for the store.
impl_crud_for_store!(BeaconBlockStore, DB_COLUMN);

impl<T: ClientDB> BeaconBlockStore<T> {
    pub fn new(db: Arc<T>) -> Self {
        Self { db }
    }

    pub fn get_deserialized(&self, hash: &Hash256) -> Result<Option<BeaconBlock>, DBError> {
        match self.get(&hash)? {
            None => Ok(None),
            Some(ssz) => {
                let (block, _) = BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| DBError {
                    message: "Bad BeaconBlock SSZ.".to_string(),
                })?;
                Ok(Some(block))
            }
        }
    }

    /// Retuns an object implementing `BeaconBlockReader`, or `None` (if hash not known).
    ///
    /// Note: Presently, this function fully deserializes a `BeaconBlock` and returns that. In the
    /// future, it would be ideal to return an object capable of reading directly from serialized
    /// SSZ bytes.
    pub fn get_reader(&self, hash: &Hash256) -> Result<Option<impl BeaconBlockReader>, DBError> {
        match self.get(&hash)? {
            None => Ok(None),
            Some(ssz) => {
                let (block, _) = BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| DBError {
                    message: "Bad BeaconBlock SSZ.".to_string(),
                })?;
                Ok(Some(block))
            }
        }
    }

    /// Retrieve the block at a slot given a "head_hash" and a slot.
    ///
    /// A "head_hash" must be a block hash with a slot number greater than or equal to the desired
    /// slot.
    ///
    /// This function will read each block down the chain until it finds a block with the given
    /// slot number. If the slot is skipped, the function will return None.
    ///
    /// If a block is found, a tuple of (block_hash, serialized_block) is returned.
    ///
    /// Note: this function uses a loop instead of recursion as the compiler is over-strict when it
    /// comes to recursion and the `impl Trait` pattern. See:
    /// https://stackoverflow.com/questions/54032940/using-impl-trait-in-a-recursive-function
    pub fn block_at_slot(
        &self,
        head_hash: &Hash256,
        slot: u64,
    ) -> Result<Option<(Hash256, impl BeaconBlockReader)>, BeaconBlockAtSlotError> {
        let mut current_hash = *head_hash;

        loop {
            if let Some(block_reader) = self.get_reader(&current_hash)? {
                if block_reader.slot() == slot {
                    break Ok(Some((current_hash, block_reader)));
                } else if block_reader.slot() < slot {
                    break Ok(None);
                } else {
                    current_hash = block_reader.parent_root();
                }
            } else {
                break Err(BeaconBlockAtSlotError::UnknownBeaconBlock(current_hash));
            }
        }
    }
}

impl From<DBError> for BeaconBlockAtSlotError {
    fn from(e: DBError) -> Self {
        BeaconBlockAtSlotError::DBError(e.message)
    }
}

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

    use std::sync::Arc;
    use std::thread;

    use ssz::ssz_encode;
    use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};
    use types::BeaconBlock;
    use types::Hash256;

    test_crud_for_store!(BeaconBlockStore, DB_COLUMN);

    #[test]
    fn head_hash_slot_too_low() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));
        let mut rng = XorShiftRng::from_seed([42; 16]);

        let mut block = BeaconBlock::random_for_test(&mut rng);
        block.slot = 10;

        let block_root = block.canonical_root();
        bs.put(&block_root, &ssz_encode(&block)).unwrap();

        let result = bs.block_at_slot(&block_root, 11).unwrap();
        assert_eq!(result, None);
    }

    #[test]
    fn test_invalid_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let store = BeaconBlockStore::new(db.clone());

        let ssz = "definitly not a valid block".as_bytes();
        let hash = &Hash256::from("some hash".as_bytes());

        db.put(DB_COLUMN, hash, ssz).unwrap();
        assert_eq!(
            store.block_at_slot(hash, 42),
            Err(BeaconBlockAtSlotError::DBError(
                "Bad BeaconBlock SSZ.".into()
            ))
        );
    }

    #[test]
    fn test_unknown_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let store = BeaconBlockStore::new(db.clone());

        let ssz = "some bytes".as_bytes();
        let hash = &Hash256::from("some hash".as_bytes());
        let other_hash = &Hash256::from("another hash".as_bytes());

        db.put(DB_COLUMN, hash, ssz).unwrap();
        assert_eq!(
            store.block_at_slot(other_hash, 42),
            Err(BeaconBlockAtSlotError::UnknownBeaconBlock(*other_hash))
        );
    }

    #[test]
    fn test_block_store_on_memory_db() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));

        let thread_count = 10;
        let write_count = 10;

        // We're expecting the product of these numbers to fit in one byte.
        assert!(thread_count * write_count <= 255);

        let mut handles = vec![];
        for t in 0..thread_count {
            let wc = write_count;
            let bs = bs.clone();
            let handle = thread::spawn(move || {
                for w in 0..wc {
                    let key = (t * w) as u8;
                    let val = 42;
                    bs.put(&[key][..].into(), &vec![val]).unwrap();
                }
            });
            handles.push(handle);
        }

        for handle in handles {
            handle.join().unwrap();
        }

        for t in 0..thread_count {
            for w in 0..write_count {
                let key = (t * w) as u8;
                assert!(bs.exists(&[key][..].into()).unwrap());
                let val = bs.get(&[key][..].into()).unwrap().unwrap();
                assert_eq!(vec![42], val);
            }
        }
    }

    #[test]
    fn test_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));
        let mut rng = XorShiftRng::from_seed([42; 16]);

        // Specify test block parameters.
        let hashes = [
            Hash256::from(&[0; 32][..]),
            Hash256::from(&[1; 32][..]),
            Hash256::from(&[2; 32][..]),
            Hash256::from(&[3; 32][..]),
            Hash256::from(&[4; 32][..]),
        ];
        let parent_hashes = [
            Hash256::from(&[255; 32][..]), // Genesis block.
            Hash256::from(&[0; 32][..]),
            Hash256::from(&[1; 32][..]),
            Hash256::from(&[2; 32][..]),
            Hash256::from(&[3; 32][..]),
        ];
        let slots = [0, 1, 3, 4, 5];

        // Generate a vec of random blocks and store them in the DB.
        let block_count = 5;
        let mut blocks: Vec<BeaconBlock> = Vec::with_capacity(5);
        for i in 0..block_count {
            let mut block = BeaconBlock::random_for_test(&mut rng);

            block.parent_root = parent_hashes[i];
            block.slot = slots[i];

            let ssz = ssz_encode(&block);
            db.put(DB_COLUMN, &hashes[i], &ssz).unwrap();

            blocks.push(block);
        }

        // Test that certain slots can be reached from certain hashes.
        let test_cases = vec![(4, 4), (4, 3), (4, 2), (4, 1), (4, 0)];
        for (hashes_index, slot_index) in test_cases {
            let (matched_block_hash, reader) = bs
                .block_at_slot(&hashes[hashes_index], slots[slot_index])
                .unwrap()
                .unwrap();
            assert_eq!(matched_block_hash, hashes[slot_index]);
            assert_eq!(reader.slot(), slots[slot_index]);
        }

        let ssz = bs.block_at_slot(&hashes[4], 2).unwrap();
        assert_eq!(ssz, None);

        let ssz = bs.block_at_slot(&hashes[4], 6).unwrap();
        assert_eq!(ssz, None);

        let bad_hash = &Hash256::from("unknown".as_bytes());
        let ssz = bs.block_at_slot(bad_hash, 2);
        assert_eq!(
            ssz,
            Err(BeaconBlockAtSlotError::UnknownBeaconBlock(*bad_hash))
        );
    }
}
<commit_msg>Update BeaconBlockStore to use Slot newtype<commit_after>use super::BLOCKS_DB_COLUMN as DB_COLUMN;
use super::{ClientDB, DBError};
use ssz::Decodable;
use std::sync::Arc;
use types::{readers::BeaconBlockReader, BeaconBlock, Hash256, Slot};

#[derive(Clone, Debug, PartialEq)]
pub enum BeaconBlockAtSlotError {
    UnknownBeaconBlock(Hash256),
    InvalidBeaconBlock(Hash256),
    DBError(String),
}

pub struct BeaconBlockStore<T>
where
    T: ClientDB,
{
    db: Arc<T>,
}

// Implements `put`, `get`, `exists` and `delete` for the store.
impl_crud_for_store!(BeaconBlockStore, DB_COLUMN);

impl<T: ClientDB> BeaconBlockStore<T> {
    pub fn new(db: Arc<T>) -> Self {
        Self { db }
    }

    pub fn get_deserialized(&self, hash: &Hash256) -> Result<Option<BeaconBlock>, DBError> {
        match self.get(&hash)? {
            None => Ok(None),
            Some(ssz) => {
                let (block, _) = BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| DBError {
                    message: "Bad BeaconBlock SSZ.".to_string(),
                })?;
                Ok(Some(block))
            }
        }
    }

    /// Retuns an object implementing `BeaconBlockReader`, or `None` (if hash not known).
    ///
    /// Note: Presently, this function fully deserializes a `BeaconBlock` and returns that. In the
    /// future, it would be ideal to return an object capable of reading directly from serialized
    /// SSZ bytes.
    pub fn get_reader(&self, hash: &Hash256) -> Result<Option<impl BeaconBlockReader>, DBError> {
        match self.get(&hash)? {
            None => Ok(None),
            Some(ssz) => {
                let (block, _) = BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| DBError {
                    message: "Bad BeaconBlock SSZ.".to_string(),
                })?;
                Ok(Some(block))
            }
        }
    }

    /// Retrieve the block at a slot given a "head_hash" and a slot.
    ///
    /// A "head_hash" must be a block hash with a slot number greater than or equal to the desired
    /// slot.
    ///
    /// This function will read each block down the chain until it finds a block with the given
    /// slot number. If the slot is skipped, the function will return None.
    ///
    /// If a block is found, a tuple of (block_hash, serialized_block) is returned.
    ///
    /// Note: this function uses a loop instead of recursion as the compiler is over-strict when it
    /// comes to recursion and the `impl Trait` pattern. See:
    /// https://stackoverflow.com/questions/54032940/using-impl-trait-in-a-recursive-function
    pub fn block_at_slot(
        &self,
        head_hash: &Hash256,
        slot: Slot,
    ) -> Result<Option<(Hash256, impl BeaconBlockReader)>, BeaconBlockAtSlotError> {
        let mut current_hash = *head_hash;

        loop {
            if let Some(block_reader) = self.get_reader(&current_hash)? {
                if block_reader.slot() == slot {
                    break Ok(Some((current_hash, block_reader)));
                } else if block_reader.slot() < slot {
                    break Ok(None);
                } else {
                    current_hash = block_reader.parent_root();
                }
            } else {
                break Err(BeaconBlockAtSlotError::UnknownBeaconBlock(current_hash));
            }
        }
    }
}

impl From<DBError> for BeaconBlockAtSlotError {
    fn from(e: DBError) -> Self {
        BeaconBlockAtSlotError::DBError(e.message)
    }
}

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

    use std::sync::Arc;
    use std::thread;

    use ssz::ssz_encode;
    use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};
    use types::BeaconBlock;
    use types::Hash256;

    test_crud_for_store!(BeaconBlockStore, DB_COLUMN);

    #[test]
    fn head_hash_slot_too_low() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));
        let mut rng = XorShiftRng::from_seed([42; 16]);

        let mut block = BeaconBlock::random_for_test(&mut rng);
        block.slot = Slot::from(10_u64);

        let block_root = block.canonical_root();
        bs.put(&block_root, &ssz_encode(&block)).unwrap();

        let result = bs.block_at_slot(&block_root, Slot::from(11_u64)).unwrap();
        assert_eq!(result, None);
    }

    #[test]
    fn test_invalid_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let store = BeaconBlockStore::new(db.clone());

        let ssz = "definitly not a valid block".as_bytes();
        let hash = &Hash256::from("some hash".as_bytes());

        db.put(DB_COLUMN, hash, ssz).unwrap();
        assert_eq!(
            store.block_at_slot(hash, Slot::from(42_u64)),
            Err(BeaconBlockAtSlotError::DBError(
                "Bad BeaconBlock SSZ.".into()
            ))
        );
    }

    #[test]
    fn test_unknown_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let store = BeaconBlockStore::new(db.clone());

        let ssz = "some bytes".as_bytes();
        let hash = &Hash256::from("some hash".as_bytes());
        let other_hash = &Hash256::from("another hash".as_bytes());

        db.put(DB_COLUMN, hash, ssz).unwrap();
        assert_eq!(
            store.block_at_slot(other_hash, Slot::from(42_u64)),
            Err(BeaconBlockAtSlotError::UnknownBeaconBlock(*other_hash))
        );
    }

    #[test]
    fn test_block_store_on_memory_db() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));

        let thread_count = 10;
        let write_count = 10;

        // We're expecting the product of these numbers to fit in one byte.
        assert!(thread_count * write_count <= 255);

        let mut handles = vec![];
        for t in 0..thread_count {
            let wc = write_count;
            let bs = bs.clone();
            let handle = thread::spawn(move || {
                for w in 0..wc {
                    let key = (t * w) as u8;
                    let val = 42;
                    bs.put(&[key][..].into(), &vec![val]).unwrap();
                }
            });
            handles.push(handle);
        }

        for handle in handles {
            handle.join().unwrap();
        }

        for t in 0..thread_count {
            for w in 0..write_count {
                let key = (t * w) as u8;
                assert!(bs.exists(&[key][..].into()).unwrap());
                let val = bs.get(&[key][..].into()).unwrap().unwrap();
                assert_eq!(vec![42], val);
            }
        }
    }

    #[test]
    fn test_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));
        let mut rng = XorShiftRng::from_seed([42; 16]);

        // Specify test block parameters.
        let hashes = [
            Hash256::from(&[0; 32][..]),
            Hash256::from(&[1; 32][..]),
            Hash256::from(&[2; 32][..]),
            Hash256::from(&[3; 32][..]),
            Hash256::from(&[4; 32][..]),
        ];
        let parent_hashes = [
            Hash256::from(&[255; 32][..]), // Genesis block.
            Hash256::from(&[0; 32][..]),
            Hash256::from(&[1; 32][..]),
            Hash256::from(&[2; 32][..]),
            Hash256::from(&[3; 32][..]),
        ];
        let slots: Vec<Slot> = vec![0, 1, 3, 4, 5].iter().map(|x| Slot::new(*x)).collect();

        // Generate a vec of random blocks and store them in the DB.
        let block_count = 5;
        let mut blocks: Vec<BeaconBlock> = Vec::with_capacity(5);
        for i in 0..block_count {
            let mut block = BeaconBlock::random_for_test(&mut rng);

            block.parent_root = parent_hashes[i];
            block.slot = slots[i];

            let ssz = ssz_encode(&block);
            db.put(DB_COLUMN, &hashes[i], &ssz).unwrap();

            blocks.push(block);
        }

        // Test that certain slots can be reached from certain hashes.
        let test_cases = vec![(4, 4), (4, 3), (4, 2), (4, 1), (4, 0)];
        for (hashes_index, slot_index) in test_cases {
            let (matched_block_hash, reader) = bs
                .block_at_slot(&hashes[hashes_index], slots[slot_index])
                .unwrap()
                .unwrap();
            assert_eq!(matched_block_hash, hashes[slot_index]);
            assert_eq!(reader.slot(), slots[slot_index]);
        }

        let ssz = bs.block_at_slot(&hashes[4], Slot::new(2)).unwrap();
        assert_eq!(ssz, None);

        let ssz = bs.block_at_slot(&hashes[4], Slot::new(6)).unwrap();
        assert_eq!(ssz, None);

        let bad_hash = &Hash256::from("unknown".as_bytes());
        let ssz = bs.block_at_slot(bad_hash, Slot::new(2));
        assert_eq!(
            ssz,
            Err(BeaconBlockAtSlotError::UnknownBeaconBlock(*bad_hash))
        );
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::stdio;
use std::collections;

struct Difficulty {
    min: uint,
    max: uint
}

fn main() {

    start();
}

fn start() {
    println!("WELCOME TO HANGMAN");
    println!("Please enter a difficulty: easy, medium, or hard:");

    loop {
        io::print(">");
        let input = &stdio::stdin()
                            .read_line()
                            .ok()
                            .expect("Failed to read line.");

        let difficulty_opt = match input.as_slice() {
            "easy\n"   => Some(Difficulty { min: 3, max: 5 }),
            "medium\n" => Some(Difficulty { min: 5, max: 7 }),
            "hard\n"   => Some(Difficulty { min: 7, max: 9 }),
            _          => None
        };

        let difficulty = match difficulty_opt {
            Some(d) => d,
            None    => {
                println!("Invalid input.");
                println!("Please enter a difficulty: easy, medium, or hard:");
                continue
            }
        };

        println!("Minimum word length set to {}", difficulty.min);
        println!("Maximum word length set to {}", difficulty.max);

        let words = get_words(&difficulty);

    }
}

fn get_words(difficulty: &Difficulty) -> Vec<String> {
    let mut words = Vec::new();
    let min = difficulty.min;
    let max = difficulty.max;

    let path = Path::new("/usr/share/dict/words");
    let words_file = io::File::open(&path).ok().expect("Error opening file.");
    let mut reader = io::BufferedReader::new(words_file);
    let mut counter = 0u;
    loop {
        match reader.read_line() {
            Ok(line) => {
                if min < line.len() && line.len() < max {
                    words.push(line
                               .as_slice()
                               .trim_right_chars('\n')
                               .to_string());
                    counter += 1;
                }
            }
            Err(why) => match why.kind {
                io::EndOfFile => break,
                _             => fail!("Error reading file: {}", why)
            }
        }
    }
    println!("Read in {} words.", counter);
    words
}

<commit_msg>I don't think I need to copy the whole `words` array<commit_after>use std::io;
use std::io::stdio;
use std::collections;

struct Difficulty {
    min: uint,
    max: uint
}

fn main() {

    start();
}

fn start() {
    println!("WELCOME TO HANGMAN");
    println!("Please enter a difficulty: easy, medium, or hard:");

    loop {
        io::print(">");
        let input = &stdio::stdin()
                            .read_line()
                            .ok()
                            .expect("Failed to read line.");

        let difficulty_opt = match input.as_slice() {
            "easy\n"   => Some(Difficulty { min: 3, max: 5 }),
            "medium\n" => Some(Difficulty { min: 5, max: 7 }),
            "hard\n"   => Some(Difficulty { min: 7, max: 9 }),
            _          => None
        };

        let difficulty = match difficulty_opt {
            Some(d) => d,
            None    => {
                println!("Invalid input.");
                println!("Please enter a difficulty: easy, medium, or hard:");
                continue
            }
        };

        println!("Minimum word length set to {}", difficulty.min);
        println!("Maximum word length set to {}", difficulty.max);

        let words = *get_words(&difficulty);

    }
}

fn get_words(difficulty: &Difficulty) -> Box<Vec<String>> {
    let mut words = Vec::new();
    let min = difficulty.min;
    let max = difficulty.max;

    let path = Path::new("/usr/share/dict/words");
    let words_file = io::File::open(&path).ok().expect("Error opening file.");
    let mut reader = io::BufferedReader::new(words_file);
    let mut counter = 0u;
    loop {
        match reader.read_line() {
            Ok(line) => {
                if min < line.len() && line.len() < max {
                    words.push(line
                               .as_slice()
                               .trim_right_chars('\n')
                               .to_string());
                    counter += 1;
                }
            }
            Err(why) => match why.kind {
                io::EndOfFile => break,
                _             => fail!("Error reading file: {}", why)
            }
        }
    }
    println!("Read in {} words.", counter);
    box words
}

<|endoftext|>


<commit_before>use super::connection::Connection;
use mio::channel::{channel, Sender, Receiver};
use std::thread;
use mio::{Poll, Token, Ready, PollOpt, Events};
use mio::unix::UnixReady;
use slab::Slab;
use radium_protocol::{Message, ReadValue};
use libradium::Entry;
use std::io;
use super::entry::EntryData;

const MESSAGE: Token = Token(10_000_000);

enum WorkerMessage {
    Connection(Connection),
    Push(Entry<EntryData>)
}

struct Worker {
    connections: Connections,
    poll: Poll,
    receiver: Receiver<WorkerMessage>
}

pub struct Connections {
    inner: Slab<Connection, Token>
}

pub struct Pool {
    next_pool: usize,
    num_threads: usize,
    threads: Vec<Sender<WorkerMessage>>,
}

impl Worker {
    pub fn new(poll: Poll, receiver: Receiver<WorkerMessage>) -> Self {
        Worker {
            connections: Connections::with_capacity(128),
            poll: poll,
            receiver: receiver
        }
    }

    pub fn spawn() -> io::Result<Sender<WorkerMessage>> {
        let (sender, receiver) = channel::<WorkerMessage>();
        let poll = Poll::new()?;
        poll.register(&receiver, MESSAGE, Ready::readable(), PollOpt::edge())?;

        let mut worker = Worker::new(poll, receiver);

        thread::spawn(move || {
            worker.run();
        });

        Ok(sender)
    }

    pub fn run(&mut self) {
        let mut events = Events::with_capacity(1024);

        loop {
            self.poll.poll(&mut events, None).unwrap();

            for i in 0..events.len() {
                let event = events.get(i).unwrap();
                let token = event.token();

                match token {
                    MESSAGE => {
                        let msg = self.receiver.try_recv().unwrap();

                        match msg {
                            WorkerMessage::Connection(conn) => {
                                let (conn_ref, token) = self.connections.add_conn(conn);

                                self.poll.register(conn_ref, token, Ready::readable(), PollOpt::edge())
                                    .unwrap();
                            },
                            WorkerMessage::Push(entry) => {
                                debug!("Entry has expired: {:?}", entry.id())
                            }
                        }
                    },
                    _ if self.connections.has_conn(token) => {
                        let ready = event.readiness();
                        let conn = self.connections.get_conn(token).unwrap();

                        if UnixReady::from(ready).is_hup() {
                            self.poll.deregister(conn);
                            return;
                            // TODO: disconnect
                        }

                        if !ready.is_readable() {
                            continue;
                        }

                        let msg = conn.read_value::<Message>().unwrap();

                        debug!("Received {:?}", msg.message_type());
                    },
                    _ => unreachable!()
                }
            }
        }
    }
}

impl Connections {
    pub fn with_capacity(capacity: usize) -> Self {
        Connections {
            inner: Slab::with_capacity(capacity)
        }
    }

    pub fn has_conn(&self, token: Token) -> bool {
        self.inner.get(token).is_some()
    }

    pub fn get_conn(&mut self, token: Token) -> Option<&mut Connection> {
        self.inner.get_mut(token)
    }

    pub fn add_conn(&mut self, conn: Connection) -> (&Connection, Token) {
        // TODO: delegate .unwrap() to caller
        let token = {
            let entry = self.inner.vacant_entry().unwrap();

            entry.insert(conn).index()
        };
        let conn_ref = self.inner.get(token).unwrap();

        (conn_ref, token)
    }
}

impl Pool {
    pub fn new(num_threads: usize) -> Pool {
        // TODO: don't unwrap here
        let threads = (0..num_threads)
            .map(|_| Worker::spawn().unwrap())
            .collect();

        Pool { threads, num_threads, next_pool: 0 }
    }

    pub fn register(&mut self, conn: Connection) {
        {
            let sender = self.threads.get(self.next_pool).unwrap();
            sender.send(WorkerMessage::Connection(conn));
        }

        self.next_pool();
    }

    pub fn push_expired(&self, entry: Entry<EntryData>) {
        for thread in &self.threads {
            // TODO: we probably shouldn't clone the entry for every thread
            thread.send(WorkerMessage::Push(entry.clone()));
        }
    }

    fn next_pool(&mut self) {
        self.next_pool += 1;

        if self.next_pool == self.num_threads {
            self.next_pool = 0;
        }
    }
}<commit_msg>Add that missing line<commit_after>use super::connection::Connection;
use mio::channel::{channel, Sender, Receiver};
use std::thread;
use mio::{Poll, Token, Ready, PollOpt, Events};
use mio::unix::UnixReady;
use slab::Slab;
use radium_protocol::{Message, ReadValue};
use libradium::Entry;
use std::io;
use super::entry::EntryData;

const MESSAGE: Token = Token(10_000_000);

enum WorkerMessage {
    Connection(Connection),
    Push(Entry<EntryData>)
}

struct Worker {
    connections: Connections,
    poll: Poll,
    receiver: Receiver<WorkerMessage>
}

pub struct Connections {
    inner: Slab<Connection, Token>
}

pub struct Pool {
    next_pool: usize,
    num_threads: usize,
    threads: Vec<Sender<WorkerMessage>>,
}

impl Worker {
    pub fn new(poll: Poll, receiver: Receiver<WorkerMessage>) -> Self {
        Worker {
            connections: Connections::with_capacity(128),
            poll: poll,
            receiver: receiver
        }
    }

    pub fn spawn() -> io::Result<Sender<WorkerMessage>> {
        let (sender, receiver) = channel::<WorkerMessage>();

        let poll = Poll::new()?;
        poll.register(&receiver, MESSAGE, Ready::readable(), PollOpt::edge())?;

        let mut worker = Worker::new(poll, receiver);

        thread::spawn(move || {
            worker.run();
        });

        Ok(sender)
    }

    pub fn run(&mut self) {
        let mut events = Events::with_capacity(1024);

        loop {
            self.poll.poll(&mut events, None).unwrap();

            for i in 0..events.len() {
                let event = events.get(i).unwrap();
                let token = event.token();

                match token {
                    MESSAGE => {
                        let msg = self.receiver.try_recv().unwrap();

                        match msg {
                            WorkerMessage::Connection(conn) => {
                                let (conn_ref, token) = self.connections.add_conn(conn);

                                self.poll.register(conn_ref, token, Ready::readable(), PollOpt::edge())
                                    .unwrap();
                            },
                            WorkerMessage::Push(entry) => {
                                debug!("Entry has expired: {:?}", entry.id())
                            }
                        }
                    },
                    _ if self.connections.has_conn(token) => {
                        let ready = event.readiness();
                        let conn = self.connections.get_conn(token).unwrap();

                        if UnixReady::from(ready).is_hup() {
                            self.poll.deregister(conn);
                            return;
                            // TODO: disconnect
                        }

                        if !ready.is_readable() {
                            continue;
                        }

                        let msg = conn.read_value::<Message>().unwrap();

                        debug!("Received {:?}", msg.message_type());
                    },
                    _ => unreachable!()
                }
            }
        }
    }
}

impl Connections {
    pub fn with_capacity(capacity: usize) -> Self {
        Connections {
            inner: Slab::with_capacity(capacity)
        }
    }

    pub fn has_conn(&self, token: Token) -> bool {
        self.inner.get(token).is_some()
    }

    pub fn get_conn(&mut self, token: Token) -> Option<&mut Connection> {
        self.inner.get_mut(token)
    }

    pub fn add_conn(&mut self, conn: Connection) -> (&Connection, Token) {
        // TODO: delegate .unwrap() to caller
        let token = {
            let entry = self.inner.vacant_entry().unwrap();

            entry.insert(conn).index()
        };
        let conn_ref = self.inner.get(token).unwrap();

        (conn_ref, token)
    }
}

impl Pool {
    pub fn new(num_threads: usize) -> Pool {
        // TODO: don't unwrap here
        let threads = (0..num_threads)
            .map(|_| Worker::spawn().unwrap())
            .collect();

        Pool { threads, num_threads, next_pool: 0 }
    }

    pub fn register(&mut self, conn: Connection) {
        {
            let sender = self.threads.get(self.next_pool).unwrap();
            sender.send(WorkerMessage::Connection(conn));
        }

        self.next_pool();
    }

    pub fn push_expired(&self, entry: Entry<EntryData>) {
        for thread in &self.threads {
            // TODO: we probably shouldn't clone the entry for every thread
            thread.send(WorkerMessage::Push(entry.clone()));
        }
    }

    fn next_pool(&mut self) {
        self.next_pool += 1;

        if self.next_pool == self.num_threads {
            self.next_pool = 0;
        }
    }
}<|endoftext|>