<commit_before>//! The code in this module gathers up all of the inherent impls in
//! the current crate and organizes them in a map. It winds up
//! touching the whole crate and thus must be recomputed completely
//! for any change, but it is very cheap to compute. In practice, most
//! code in the compiler never *directly* requests this map. Instead,
//! it requests the inherent impls specific to some type (via
//! `tcx.inherent_impls(def_id)`). That value, however,
//! is computed by selecting an idea from this table.

use rustc::dep_graph::DepKind;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::{self, CrateInherentImpls, TyCtxt};

use syntax::ast;
use syntax_pos::Span;

/// On-demand query: yields a map containing all types mapped to their inherent impls.
pub fn crate_inherent_impls<'tcx>(
    tcx: TyCtxt<'tcx>,
    crate_num: CrateNum,
) -> &'tcx CrateInherentImpls {
    assert_eq!(crate_num, LOCAL_CRATE);

    let krate = tcx.hir().krate();
    let mut collect = InherentCollect {
        tcx,
        impls_map: Default::default(),
    };
    krate.visit_all_item_likes(&mut collect);
    tcx.arena.alloc(collect.impls_map)
}

/// On-demand query: yields a vector of the inherent impls for a specific type.
pub fn inherent_impls<'tcx>(tcx: TyCtxt<'tcx>, ty_def_id: DefId) -> &'tcx [DefId] {
    assert!(ty_def_id.is_local());

    // NB. Until we adopt the red-green dep-tracking algorithm (see
    // [the plan] for details on that), we do some hackery here to get
    // the dependencies correct.  Basically, we use a `with_ignore` to
    // read the result we want. If we didn't have the `with_ignore`,
    // we would wind up with a dependency on the entire crate, which
    // we don't want. Then we go and add dependencies on all the impls
    // in the result (which is what we wanted).
    //
    // The result is a graph with an edge from `Hir(I)` for every impl
    // `I` defined on some type `T` to `CoherentInherentImpls(T)`,
    // thus ensuring that if any of those impls change, the set of
    // inherent impls is considered dirty.
    //
    // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4

    let result = tcx.dep_graph.with_ignore(|| {
        let crate_map = tcx.crate_inherent_impls(ty_def_id.krate);
        match crate_map.inherent_impls.get(&ty_def_id) {
            Some(v) => &v[..],
            None => &[],
        }
    });

    for &impl_def_id in &result[..] {
        let def_path_hash = tcx.def_path_hash(impl_def_id);
        tcx.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
    }

    result
}

struct InherentCollect<'tcx> {
    tcx: TyCtxt<'tcx>,
    impls_map: CrateInherentImpls,
}

impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        let ty = match item.node {
            hir::ItemKind::Impl(.., None, ref ty, _) => ty,
            _ => return
        };

        let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id);
        let self_ty = self.tcx.type_of(def_id);
        let lang_items = self.tcx.lang_items();
        match self_ty.sty {
            ty::Adt(def, _) => {
                self.check_def_id(item, def.did);
            }
            ty::Foreign(did) => {
                self.check_def_id(item, did);
            }
            ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => {
                self.check_def_id(item, data.principal_def_id().unwrap());
            }
            ty::Char => {
                self.check_primitive_impl(def_id,
                                          lang_items.char_impl(),
                                          None,
                                          "char",
                                          "char",
                                          item.span);
            }
            ty::Str => {
                self.check_primitive_impl(def_id,
                                          lang_items.str_impl(),
                                          lang_items.str_alloc_impl(),
                                          "str",
                                          "str",
                                          item.span);
            }
            ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
                self.check_primitive_impl(def_id,
                                          lang_items.slice_u8_impl(),
                                          lang_items.slice_u8_alloc_impl(),
                                          "slice_u8",
                                          "[u8]",
                                          item.span);
            }
            ty::Slice(_) => {
                self.check_primitive_impl(def_id,
                                          lang_items.slice_impl(),
                                          lang_items.slice_alloc_impl(),
                                          "slice",
                                          "[T]",
                                          item.span);
            }
            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
                self.check_primitive_impl(def_id,
                                          lang_items.const_ptr_impl(),
                                          None,
                                          "const_ptr",
                                          "*const T",
                                          item.span);
            }
            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
                self.check_primitive_impl(def_id,
                                          lang_items.mut_ptr_impl(),
                                          None,
                                          "mut_ptr",
                                          "*mut T",
                                          item.span);
            }
            ty::Int(ast::IntTy::I8) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i8_impl(),
                                          None,
                                          "i8",
                                          "i8",
                                          item.span);
            }
            ty::Int(ast::IntTy::I16) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i16_impl(),
                                          None,
                                          "i16",
                                          "i16",
                                          item.span);
            }
            ty::Int(ast::IntTy::I32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i32_impl(),
                                          None,
                                          "i32",
                                          "i32",
                                          item.span);
            }
            ty::Int(ast::IntTy::I64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i64_impl(),
                                          None,
                                          "i64",
                                          "i64",
                                          item.span);
            }
            ty::Int(ast::IntTy::I128) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i128_impl(),
                                          None,
                                          "i128",
                                          "i128",
                                          item.span);
            }
            ty::Int(ast::IntTy::Isize) => {
                self.check_primitive_impl(def_id,
                                          lang_items.isize_impl(),
                                          None,
                                          "isize",
                                          "isize",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U8) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u8_impl(),
                                          None,
                                          "u8",
                                          "u8",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U16) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u16_impl(),
                                          None,
                                          "u16",
                                          "u16",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u32_impl(),
                                          None,
                                          "u32",
                                          "u32",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u64_impl(),
                                          None,
                                          "u64",
                                          "u64",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U128) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u128_impl(),
                                          None,
                                          "u128",
                                          "u128",
                                          item.span);
            }
            ty::Uint(ast::UintTy::Usize) => {
                self.check_primitive_impl(def_id,
                                          lang_items.usize_impl(),
                                          None,
                                          "usize",
                                          "usize",
                                          item.span);
            }
            ty::Float(ast::FloatTy::F32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.f32_impl(),
                                          lang_items.f32_runtime_impl(),
                                          "f32",
                                          "f32",
                                          item.span);
            }
            ty::Float(ast::FloatTy::F64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.f64_impl(),
                                          lang_items.f64_runtime_impl(),
                                          "f64",
                                          "f64",
                                          item.span);
            }
            ty::Error => {
                return;
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 ty.span,
                                 E0118,
                                 "no base type found for inherent implementation")
                    .span_label(ty.span, "impl requires a base type")
                    .note(&format!("either implement a trait on it or create a newtype \
                                    to wrap it instead"))
                    .emit();
                return;
            }
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
    }
}

impl InherentCollect<'tcx> {
    fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
        if def_id.is_local() {
            // Add the implementation to the mapping from implementation to base
            // type def ID, if there is a base type for this implementation and
            // the implementation does not have any associated traits.
            let impl_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id);
            let vec = self.impls_map.inherent_impls.entry(def_id).or_default();
            vec.push(impl_def_id);
        } else {
            struct_span_err!(self.tcx.sess,
                             item.span,
                             E0116,
                             "cannot define inherent `impl` for a type outside of the crate \
                              where the type is defined")
                .span_label(item.span, "impl for type defined outside of crate.")
                .note("define and implement a trait or new type instead")
                .emit();
        }
    }

    fn check_primitive_impl(&self,
                            impl_def_id: DefId,
                            lang_def_id: Option<DefId>,
                            lang_def_id2: Option<DefId>,
                            lang: &str,
                            ty: &str,
                            span: Span) {
        match (lang_def_id, lang_def_id2) {
            (Some(lang_def_id), _) if lang_def_id == impl_def_id => {
                // OK
            }
            (_, Some(lang_def_id)) if lang_def_id == impl_def_id => {
                // OK
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 span,
                                 E0390,
                                 "only a single inherent implementation marked with `#[lang = \
                                  \"{}\"]` is allowed for the `{}` primitive",
                                 lang,
                                 ty)
                    .span_help(span, "consider using a trait to implement these methods")
                    .emit();
            }
        }
    }
}
<commit_msg>Clean up inherent_impls<commit_after>//! The code in this module gathers up all of the inherent impls in
//! the current crate and organizes them in a map. It winds up
//! touching the whole crate and thus must be recomputed completely
//! for any change, but it is very cheap to compute. In practice, most
//! code in the compiler never *directly* requests this map. Instead,
//! it requests the inherent impls specific to some type (via
//! `tcx.inherent_impls(def_id)`). That value, however,
//! is computed by selecting an idea from this table.

use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::{self, CrateInherentImpls, TyCtxt};

use syntax::ast;
use syntax_pos::Span;

/// On-demand query: yields a map containing all types mapped to their inherent impls.
pub fn crate_inherent_impls<'tcx>(
    tcx: TyCtxt<'tcx>,
    crate_num: CrateNum,
) -> &'tcx CrateInherentImpls {
    assert_eq!(crate_num, LOCAL_CRATE);

    let krate = tcx.hir().krate();
    let mut collect = InherentCollect {
        tcx,
        impls_map: Default::default(),
    };
    krate.visit_all_item_likes(&mut collect);
    tcx.arena.alloc(collect.impls_map)
}

/// On-demand query: yields a vector of the inherent impls for a specific type.
pub fn inherent_impls<'tcx>(tcx: TyCtxt<'tcx>, ty_def_id: DefId) -> &'tcx [DefId] {
    assert!(ty_def_id.is_local());

    let crate_map = tcx.crate_inherent_impls(ty_def_id.krate);
    match crate_map.inherent_impls.get(&ty_def_id) {
        Some(v) => &v[..],
        None => &[],
    }
}

struct InherentCollect<'tcx> {
    tcx: TyCtxt<'tcx>,
    impls_map: CrateInherentImpls,
}

impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        let ty = match item.node {
            hir::ItemKind::Impl(.., None, ref ty, _) => ty,
            _ => return
        };

        let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id);
        let self_ty = self.tcx.type_of(def_id);
        let lang_items = self.tcx.lang_items();
        match self_ty.sty {
            ty::Adt(def, _) => {
                self.check_def_id(item, def.did);
            }
            ty::Foreign(did) => {
                self.check_def_id(item, did);
            }
            ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => {
                self.check_def_id(item, data.principal_def_id().unwrap());
            }
            ty::Char => {
                self.check_primitive_impl(def_id,
                                          lang_items.char_impl(),
                                          None,
                                          "char",
                                          "char",
                                          item.span);
            }
            ty::Str => {
                self.check_primitive_impl(def_id,
                                          lang_items.str_impl(),
                                          lang_items.str_alloc_impl(),
                                          "str",
                                          "str",
                                          item.span);
            }
            ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
                self.check_primitive_impl(def_id,
                                          lang_items.slice_u8_impl(),
                                          lang_items.slice_u8_alloc_impl(),
                                          "slice_u8",
                                          "[u8]",
                                          item.span);
            }
            ty::Slice(_) => {
                self.check_primitive_impl(def_id,
                                          lang_items.slice_impl(),
                                          lang_items.slice_alloc_impl(),
                                          "slice",
                                          "[T]",
                                          item.span);
            }
            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
                self.check_primitive_impl(def_id,
                                          lang_items.const_ptr_impl(),
                                          None,
                                          "const_ptr",
                                          "*const T",
                                          item.span);
            }
            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
                self.check_primitive_impl(def_id,
                                          lang_items.mut_ptr_impl(),
                                          None,
                                          "mut_ptr",
                                          "*mut T",
                                          item.span);
            }
            ty::Int(ast::IntTy::I8) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i8_impl(),
                                          None,
                                          "i8",
                                          "i8",
                                          item.span);
            }
            ty::Int(ast::IntTy::I16) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i16_impl(),
                                          None,
                                          "i16",
                                          "i16",
                                          item.span);
            }
            ty::Int(ast::IntTy::I32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i32_impl(),
                                          None,
                                          "i32",
                                          "i32",
                                          item.span);
            }
            ty::Int(ast::IntTy::I64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i64_impl(),
                                          None,
                                          "i64",
                                          "i64",
                                          item.span);
            }
            ty::Int(ast::IntTy::I128) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i128_impl(),
                                          None,
                                          "i128",
                                          "i128",
                                          item.span);
            }
            ty::Int(ast::IntTy::Isize) => {
                self.check_primitive_impl(def_id,
                                          lang_items.isize_impl(),
                                          None,
                                          "isize",
                                          "isize",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U8) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u8_impl(),
                                          None,
                                          "u8",
                                          "u8",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U16) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u16_impl(),
                                          None,
                                          "u16",
                                          "u16",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u32_impl(),
                                          None,
                                          "u32",
                                          "u32",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u64_impl(),
                                          None,
                                          "u64",
                                          "u64",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U128) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u128_impl(),
                                          None,
                                          "u128",
                                          "u128",
                                          item.span);
            }
            ty::Uint(ast::UintTy::Usize) => {
                self.check_primitive_impl(def_id,
                                          lang_items.usize_impl(),
                                          None,
                                          "usize",
                                          "usize",
                                          item.span);
            }
            ty::Float(ast::FloatTy::F32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.f32_impl(),
                                          lang_items.f32_runtime_impl(),
                                          "f32",
                                          "f32",
                                          item.span);
            }
            ty::Float(ast::FloatTy::F64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.f64_impl(),
                                          lang_items.f64_runtime_impl(),
                                          "f64",
                                          "f64",
                                          item.span);
            }
            ty::Error => {
                return;
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 ty.span,
                                 E0118,
                                 "no base type found for inherent implementation")
                    .span_label(ty.span, "impl requires a base type")
                    .note(&format!("either implement a trait on it or create a newtype \
                                    to wrap it instead"))
                    .emit();
                return;
            }
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
    }
}

impl InherentCollect<'tcx> {
    fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
        if def_id.is_local() {
            // Add the implementation to the mapping from implementation to base
            // type def ID, if there is a base type for this implementation and
            // the implementation does not have any associated traits.
            let impl_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id);
            let vec = self.impls_map.inherent_impls.entry(def_id).or_default();
            vec.push(impl_def_id);
        } else {
            struct_span_err!(self.tcx.sess,
                             item.span,
                             E0116,
                             "cannot define inherent `impl` for a type outside of the crate \
                              where the type is defined")
                .span_label(item.span, "impl for type defined outside of crate.")
                .note("define and implement a trait or new type instead")
                .emit();
        }
    }

    fn check_primitive_impl(&self,
                            impl_def_id: DefId,
                            lang_def_id: Option<DefId>,
                            lang_def_id2: Option<DefId>,
                            lang: &str,
                            ty: &str,
                            span: Span) {
        match (lang_def_id, lang_def_id2) {
            (Some(lang_def_id), _) if lang_def_id == impl_def_id => {
                // OK
            }
            (_, Some(lang_def_id)) if lang_def_id == impl_def_id => {
                // OK
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 span,
                                 E0390,
                                 "only a single inherent implementation marked with `#[lang = \
                                  \"{}\"]` is allowed for the `{}` primitive",
                                 lang,
                                 ty)
                    .span_help(span, "consider using a trait to implement these methods")
                    .emit();
            }
        }
    }
}
<|endoftext|>


<commit_before>use bifrost::utils::fut_exec::wait;
use client::AsyncClient;
use cuckoofilter::*;
use dovahkiin::types::custom_types::bytes::SmallBytes;
use dovahkiin::types::custom_types::id::Id;
use dovahkiin::types::custom_types::map::Map;
use dovahkiin::types::type_id_of;
use dovahkiin::types::value::ToValue;
use index::btree::Ordering;
use index::id_from_key;
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use parking_lot::Mutex;
use parking_lot::RwLock;
use ram::cell::Cell;
use ram::types::*;
use std::cell::RefCell;
use std::collections::btree_map::Range;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeMap, BTreeSet, LinkedList};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use utils::lru_cache::LRUCache;

// LevelTree items cannot been added or removed individually
// Items must been merged from higher level in bulk
// Deletion will be performed when merging to or from higher level tree
// Because tree update will not to be performed in parallel. Unlike memtable, a single r/w lock
// should be sufficient. Thus concurrency control will be simple and efficient.

type Tombstones = BTreeSet<EntryKey>;
type PageCache<S> = Arc<Mutex<LRUCache<Id, Arc<SSPage<S>>>>>;

const PAGE_SCHEMA: &'static str = "NEB_SSTABLE_PAGE";

lazy_static! {
    static ref PAGE_SCHEMA_HASH: u32 = key_hash(PAGE_SCHEMA) as u32;
}

pub struct LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    neb_client: Arc<AsyncClient>,
    index: BTreeMap<EntryKey, Id>,
    tombstones: Tombstones,
    filter: CuckooFilter<DefaultHasher>,
    pages: PageCache<S>,
    marker: PhantomData<S>,
}
struct SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    id: Id,
    slice: S,
}

impl<S> SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn from_cell(cell: Cell) -> Self {
        let mut slice = S::init();
        let slice_len = slice.as_slice().len();
        let cell_id = cell.id();
        let keys = cell.data;
        let keys_len = keys.len().unwrap();
        debug_assert!(slice_len == keys_len);
        let keys_array = if let Value::PrimArray(PrimitiveArray::SmallBytes(ref array)) = keys {
            array
        } else {
            panic!()
        };
        for (i, val) in keys_array.iter().enumerate() {
            slice.as_slice()[i] = EntryKey::from(val.as_slice());
        }
        Self {
            id: cell_id,
            slice,
        }
    }
}

pub fn page_slice_to_cell<S>(slice: S, id: &Id) -> Cell
where
    S: Slice<Item = EntryKey>,
{
    let value = slice
        .as_slice_immute()
        .iter()
        .map(|key| SmallBytes::from_vec(key.as_slice().to_vec()))
        .collect_vec()
        .value();
    Cell::new_with_id(*PAGE_SCHEMA_HASH, id, value)
}

impl<S> LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn new(neb_client: &Arc<AsyncClient>) -> Self {
        let client = neb_client.clone();
        Self {
            neb_client: neb_client.clone(),
            index: BTreeMap::new(),
            tombstones: Tombstones::new(),
            filter: CuckooFilter::new(), // TODO: carefully set the capacity
            pages: Arc::new(Mutex::new(LRUCache::new(
                100,
                move |id| {
                    wait(client.read_cell(*id))
                        .unwrap()
                        .map(|cell| Arc::new(SSPage::from_cell(cell)))
                        .ok()
                },
                |_, _| {
                    // will do nothing on evict for pages will be write to back storage once updated
                },
            ))),
            marker: PhantomData {},
        }
    }

    pub fn seek(&self, key: &EntryKey, ordering: Ordering) -> RTCursor<S> {
        let mut range = match ordering {
            Ordering::Forward => self.index.range::<EntryKey, _>(key..),
            Ordering::Backward => self.index.range::<EntryKey, _>(..=key),
        };
        let first = match ordering {
            Ordering::Forward => range.next(),
            Ordering::Backward => range.next_back(),
        }
        .map(|(_, page_id)| self.pages.lock().get_or_fetch(page_id).unwrap().clone());

        let (pos, page_len) = if let Some(ref page) = first {
            (
                page.slice
                    .as_slice_immute()
                    .binary_search(key)
                    .unwrap_or_else(|i| i),
                page.slice.as_slice_immute().len(),
            )
        } else {
            (0, 0)
        };
        let mut cursor = RTCursor {
            ordering,
            range,
            page_len,
            current: first,
            index: pos,
            cache: self.pages.clone(),
        };

        if cursor.current.is_some() {
            match ordering {
                Ordering::Forward => {
                    if pos >= page_len {
                        cursor.next();
                    }
                }
                Ordering::Backward => {}
            }
        }

        cursor
    }

    pub fn merge(&mut self, mut source: Vec<EntryKey>, tombstones: &mut Tombstones) {
        let mut pages_cache = self.pages.lock();
        let (keys_to_removed, mut merged, mut ids_to_reuse) = {
            let (target_keys, target_pages): (Vec<_>, Vec<_>) = {
                let first = source.first().unwrap();
                let last = source.last().unwrap();
                self.index
                    .range::<EntryKey, _>(first..=last)
                    .map(|(k, id)| (k, pages_cache.get_or_fetch(id).unwrap().clone()))
                    .unzip()
            };
            let page_size = target_pages.first().unwrap().slice.len();
            let target_page_ids = target_pages.iter().map(|p| p.id).collect::<LinkedList<_>>();
            let mut target = target_pages
                .iter()
                .map(|page| page.slice.as_slice_immute())
                .flat_map(|x| x)
                .map(|x| (*x).clone())
                .collect_vec();

            let mut merged: Vec<S> = vec![S::init()];
            let src_len = source.len();
            let tgt_len = target.len();
            let mut srci = 0;
            let mut tgti = 0;

            let mut merging_slice_i = 0;

            while srci < src_len || tgti < tgt_len {
                let mut from_source = false;
                let mut lowest: &mut EntryKey = if srci >= src_len {
                    // source overflowed
                    tgti += 1;
                    &mut target[tgti - 1]
                } else if tgti >= tgt_len {
                    // target overflowed
                    srci += 1;
                    from_source = true;
                    &mut source[srci - 1]
                } else {
                    // normal case, compare
                    let t = &mut target[tgti];
                    let s = &mut source[srci];
                    if t <= s {
                        tgti += 1;
                        t
                    } else {
                        srci += 1;
                        from_source = true;
                        s
                    }
                };
                if from_source {
                    if tombstones.remove(lowest) {
                        continue;
                    }
                } else {
                    if self.tombstones.remove(lowest) {
                        continue;
                    }
                }
                mem::swap(
                    &mut merged.last_mut().unwrap().as_slice()[merging_slice_i],
                    lowest,
                );
                merging_slice_i += 1;
                if merging_slice_i >= page_size {
                    merging_slice_i = 0;
                    merged.push(S::init());
                }
            }
            if merging_slice_i == 0 {
                let merged_len = merged.len();
                merged.remove(merged_len - 1);
            }
            (
                target_keys.into_iter().map(|x| x.clone()).collect_vec(),
                merged,
                target_page_ids
            )
        };

        for k in keys_to_removed {
            self.index.remove(&k).unwrap();
        }

        for id in &ids_to_reuse {
            pages_cache.remove(id);
        }

        for mut page in merged {
            let index_key = page.as_slice()[0].clone();
            let reuse_id = ids_to_reuse.pop_back();
            let id = reuse_id.unwrap_or_else(|| Id::rand());
            let cell = page_slice_to_cell(page, &id);
            if reuse_id.is_some() {
                wait(self.neb_client.update_cell(cell)).unwrap();
            } else {
                wait(self.neb_client.write_cell(cell)).unwrap();
            }
            self.index.insert(index_key, id);
        }
    }
}

pub trait SortableEntrySlice: Sized + Slice<Item = EntryKey> {}

pub struct RTCursor<'a, S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    index: usize,
    ordering: Ordering,
    page_len: usize,
    range: Range<'a, EntryKey, Id>,
    current: Option<Arc<SSPage<S>>>,
    cache: PageCache<S>,
}

impl<'a, S> RTCursor<'a, S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn next(&mut self) -> bool {
        if self.current.is_some() {
            match self.ordering {
                Ordering::Forward => {
                    if self.index + 1 >= self.page_len {
                        if let Some((_, page_id)) = self.range.next() {
                            let next_page = self.get_page(page_id);
                            self.current = Some(next_page);
                            self.index = 0;
                        } else {
                            self.current = None;
                            return false;
                        }
                    } else {
                        self.index += 1;
                    }
                }
                Ordering::Backward => {
                    if self.index == 0 {
                        if let Some((_, page_id)) = self.range.next_back() {
                            let next_page = self.get_page(page_id);
                            self.current = Some(next_page);
                            self.index = self.page_len - 1;
                        } else {
                            self.current = None;
                            return false;
                        }
                    } else {
                        self.index -= 1;
                    }
                }
            }
            true
        } else {
            false
        }
    }

    pub fn current(&self) -> Option<&EntryKey> {
        if self.index <= 0 || self.index >= self.page_len {
            return None;
        }
        if let Some(ref page) = self.current {
            Some(&page.slice.as_slice_immute()[self.index])
        } else {
            None
        }
    }

    fn get_page(&self, id: &Id) -> Arc<SSPage<S>> {
        self.cache.lock().get_or_fetch(id).unwrap().clone()
    }
}

#[cfg(test)]
mod test {}
<commit_msg>remove filter for it will not been used<commit_after>use bifrost::utils::fut_exec::wait;
use client::AsyncClient;
use dovahkiin::types::custom_types::bytes::SmallBytes;
use dovahkiin::types::custom_types::id::Id;
use dovahkiin::types::custom_types::map::Map;
use dovahkiin::types::type_id_of;
use dovahkiin::types::value::ToValue;
use index::btree::Ordering;
use index::id_from_key;
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use parking_lot::Mutex;
use parking_lot::RwLock;
use ram::cell::Cell;
use ram::types::*;
use std::cell::RefCell;
use std::collections::btree_map::Range;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeMap, BTreeSet, LinkedList};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use utils::lru_cache::LRUCache;

// LevelTree items cannot been added or removed individually
// Items must been merged from higher level in bulk
// Deletion will be performed when merging to or from higher level tree
// Because tree update will not to be performed in parallel. Unlike memtable, a single r/w lock
// should be sufficient. Thus concurrency control will be simple and efficient.

type Tombstones = BTreeSet<EntryKey>;
type PageCache<S> = Arc<Mutex<LRUCache<Id, Arc<SSPage<S>>>>>;

const PAGE_SCHEMA: &'static str = "NEB_SSTABLE_PAGE";

lazy_static! {
    static ref PAGE_SCHEMA_HASH: u32 = key_hash(PAGE_SCHEMA) as u32;
}

pub struct LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    neb_client: Arc<AsyncClient>,
    index: BTreeMap<EntryKey, Id>,
    tombstones: Tombstones,
    pages: PageCache<S>,
    marker: PhantomData<S>,
}
struct SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    id: Id,
    slice: S,
}

impl<S> SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn from_cell(cell: Cell) -> Self {
        let mut slice = S::init();
        let slice_len = slice.as_slice().len();
        let cell_id = cell.id();
        let keys = cell.data;
        let keys_len = keys.len().unwrap();
        debug_assert!(slice_len == keys_len);
        let keys_array = if let Value::PrimArray(PrimitiveArray::SmallBytes(ref array)) = keys {
            array
        } else {
            panic!()
        };
        for (i, val) in keys_array.iter().enumerate() {
            slice.as_slice()[i] = EntryKey::from(val.as_slice());
        }
        Self {
            id: cell_id,
            slice,
        }
    }
}

pub fn page_slice_to_cell<S>(slice: S, id: &Id) -> Cell
where
    S: Slice<Item = EntryKey>,
{
    let value = slice
        .as_slice_immute()
        .iter()
        .map(|key| SmallBytes::from_vec(key.as_slice().to_vec()))
        .collect_vec()
        .value();
    Cell::new_with_id(*PAGE_SCHEMA_HASH, id, value)
}

impl<S> LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn new(neb_client: &Arc<AsyncClient>) -> Self {
        let client = neb_client.clone();
        Self {
            neb_client: neb_client.clone(),
            index: BTreeMap::new(),
            tombstones: Tombstones::new(),
            // TODO: carefully set the capacity
            pages: Arc::new(Mutex::new(LRUCache::new(
                100,
                move |id| {
                    wait(client.read_cell(*id))
                        .unwrap()
                        .map(|cell| Arc::new(SSPage::from_cell(cell)))
                        .ok()
                },
                |_, _| {
                    // will do nothing on evict for pages will be write to back storage once updated
                },
            ))),
            marker: PhantomData {},
        }
    }

    pub fn seek(&self, key: &EntryKey, ordering: Ordering) -> RTCursor<S> {
        let mut range = match ordering {
            Ordering::Forward => self.index.range::<EntryKey, _>(key..),
            Ordering::Backward => self.index.range::<EntryKey, _>(..=key),
        };
        let first = match ordering {
            Ordering::Forward => range.next(),
            Ordering::Backward => range.next_back(),
        }
        .map(|(_, page_id)| self.pages.lock().get_or_fetch(page_id).unwrap().clone());

        let (pos, page_len) = if let Some(ref page) = first {
            (
                page.slice
                    .as_slice_immute()
                    .binary_search(key)
                    .unwrap_or_else(|i| i),
                page.slice.as_slice_immute().len(),
            )
        } else {
            (0, 0)
        };
        let mut cursor = RTCursor {
            ordering,
            range,
            page_len,
            current: first,
            index: pos,
            cache: self.pages.clone(),
        };

        if cursor.current.is_some() {
            match ordering {
                Ordering::Forward => {
                    if pos >= page_len {
                        cursor.next();
                    }
                }
                Ordering::Backward => {}
            }
        }

        cursor
    }

    pub fn merge(&mut self, mut source: Vec<EntryKey>, tombstones: &mut Tombstones) {
        let mut pages_cache = self.pages.lock();
        let (keys_to_removed, mut merged, mut ids_to_reuse) = {
            let (target_keys, target_pages): (Vec<_>, Vec<_>) = {
                let first = source.first().unwrap();
                let last = source.last().unwrap();
                self.index
                    .range::<EntryKey, _>(first..=last)
                    .map(|(k, id)| (k, pages_cache.get_or_fetch(id).unwrap().clone()))
                    .unzip()
            };
            let page_size = target_pages.first().unwrap().slice.len();
            let target_page_ids = target_pages.iter().map(|p| p.id).collect::<LinkedList<_>>();
            let mut target = target_pages
                .iter()
                .map(|page| page.slice.as_slice_immute())
                .flat_map(|x| x)
                .map(|x| (*x).clone())
                .collect_vec();

            let mut merged: Vec<S> = vec![S::init()];
            let src_len = source.len();
            let tgt_len = target.len();
            let mut srci = 0;
            let mut tgti = 0;

            let mut merging_slice_i = 0;

            while srci < src_len || tgti < tgt_len {
                let mut from_source = false;
                let mut lowest: &mut EntryKey = if srci >= src_len {
                    // source overflowed
                    tgti += 1;
                    &mut target[tgti - 1]
                } else if tgti >= tgt_len {
                    // target overflowed
                    srci += 1;
                    from_source = true;
                    &mut source[srci - 1]
                } else {
                    // normal case, compare
                    let t = &mut target[tgti];
                    let s = &mut source[srci];
                    if t <= s {
                        tgti += 1;
                        t
                    } else {
                        srci += 1;
                        from_source = true;
                        s
                    }
                };
                if from_source {
                    if tombstones.remove(lowest) {
                        continue;
                    }
                } else {
                    if self.tombstones.remove(lowest) {
                        continue;
                    }
                }
                mem::swap(
                    &mut merged.last_mut().unwrap().as_slice()[merging_slice_i],
                    lowest,
                );
                merging_slice_i += 1;
                if merging_slice_i >= page_size {
                    merging_slice_i = 0;
                    merged.push(S::init());
                }
            }
            if merging_slice_i == 0 {
                let merged_len = merged.len();
                merged.remove(merged_len - 1);
            }
            (
                target_keys.into_iter().map(|x| x.clone()).collect_vec(),
                merged,
                target_page_ids
            )
        };

        for k in keys_to_removed {
            self.index.remove(&k).unwrap();
        }

        for id in &ids_to_reuse {
            pages_cache.remove(id);
        }

        for mut page in merged {
            let index_key = page.as_slice()[0].clone();
            let reuse_id = ids_to_reuse.pop_back();
            let id = reuse_id.unwrap_or_else(|| Id::rand());
            let cell = page_slice_to_cell(page, &id);
            if reuse_id.is_some() {
                wait(self.neb_client.update_cell(cell)).unwrap();
            } else {
                wait(self.neb_client.write_cell(cell)).unwrap();
            }
            self.index.insert(index_key, id);
        }
    }
}

pub trait SortableEntrySlice: Sized + Slice<Item = EntryKey> {}

pub struct RTCursor<'a, S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    index: usize,
    ordering: Ordering,
    page_len: usize,
    range: Range<'a, EntryKey, Id>,
    current: Option<Arc<SSPage<S>>>,
    cache: PageCache<S>,
}

impl<'a, S> RTCursor<'a, S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn next(&mut self) -> bool {
        if self.current.is_some() {
            match self.ordering {
                Ordering::Forward => {
                    if self.index + 1 >= self.page_len {
                        if let Some((_, page_id)) = self.range.next() {
                            let next_page = self.get_page(page_id);
                            self.current = Some(next_page);
                            self.index = 0;
                        } else {
                            self.current = None;
                            return false;
                        }
                    } else {
                        self.index += 1;
                    }
                }
                Ordering::Backward => {
                    if self.index == 0 {
                        if let Some((_, page_id)) = self.range.next_back() {
                            let next_page = self.get_page(page_id);
                            self.current = Some(next_page);
                            self.index = self.page_len - 1;
                        } else {
                            self.current = None;
                            return false;
                        }
                    } else {
                        self.index -= 1;
                    }
                }
            }
            true
        } else {
            false
        }
    }

    pub fn current(&self) -> Option<&EntryKey> {
        if self.index <= 0 || self.index >= self.page_len {
            return None;
        }
        if let Some(ref page) = self.current {
            Some(&page.slice.as_slice_immute()[self.index])
        } else {
            None
        }
    }

    fn get_page(&self, id: &Id) -> Arc<SSPage<S>> {
        self.cache.lock().get_or_fetch(id).unwrap().clone()
    }
}

#[cfg(test)]
mod test {}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, SubCommand, ErrorKind, Arg};

static HELP: &'static str = "clap-test v1.4.8
Kevin K. <kbknapp@gmail.com>
tests clap library

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

FLAGS:
    -f, --flag       tests flags
    -F               tests flags with exclusions
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -O, --Option <option3>           specific vals [values: fast, slow]
        --long-option-2 <option2>    tests long options with exclusions
        --maxvals3 <maxvals>...      Tests 3 max vals
        --minvals2 <minvals>...      Tests 2 min vals
        --multvals <one> <two>       Tests mutliple values, not mult occs
        --multvalsmo <one> <two>     Tests mutliple values, and mult occs
    -o, --option <opt>...            tests options

ARGS:
    <positional>        tests positionals
    <positional2>       tests positionals with exclusions
    <positional3>...    tests specific values [values: vi, emacs]

SUBCOMMANDS:
    help      Prints this message or the help of the given subcommand(s)
    subcmd    tests subcommands";

static AFTER_HELP: &'static str = "some text that comes before the help

clap-test v1.4.8
tests clap library

USAGE:
    clap-test

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

some text that comes after the help";

static SC_HELP: &'static str = "subcmd 0.1
Kevin K. <kbknapp@gmail.com>
tests subcommands

USAGE:
    subcmd [FLAGS] [OPTIONS] [--] [scpositional]

FLAGS:
    -f, --flag    tests flags

OPTIONS:
    -o, --option <scoption>...    tests options

ARGS:
    <scpositional>    tests positionals";

static MULTI_SC_HELP: &'static str = "ctest-subcmd-multi 0.1
Kevin K. <kbknapp@gmail.com>
tests subcommands

USAGE:
    ctest subcmd multi [FLAGS] [OPTIONS]

FLAGS:
    -f, --flag       tests flags
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -o, --option <scoption>...    tests options";

static ISSUE_626_CUTOFF: &'static str = "ctest 0.1

USAGE:
    ctest [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -c, --cafe <FILE>    A coffeehouse, coffee shop, or café is an
                         establishment which primarily serves hot
                         coffee, related coffee beverages (e.g., café
                         latte, cappuccino, espresso), tea, and other
                         hot beverages. Some coffeehouses also serve
                         cold beverages such as iced coffee and iced
                         tea. Many cafés also serve some type of
                         food, such as light snacks, muffins, or
                         pastries.";

static ISSUE_626_PANIC: &'static str = "ctest 0.1

USAGE:
    ctest [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -c, --cafe <FILE>
            La culture du café est très développée
            dans de nombreux pays à climat chaud
            d\'Amérique, d\'Afrique et d\'Asie, dans
            des plantations qui sont cultivées pour
            les marchés d\'exportation. Le café est
            souvent une contribution majeure aux
            exportations des régions productrices.";

static HIDE_POS_VALS: &'static str = "ctest 0.1

USAGE:
    ctest [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -c, --cafe <FILE>    A coffeehouse, coffee shop, or café.
    -p, --pos <VAL>      Some vals [values: fast, slow]";

static OLD_NEWLINE_CHARS: &'static str = "ctest 0.1

USAGE:
    ctest [FLAGS]

FLAGS:
    -h, --help       Prints help information
    -m               Some help with some wrapping
                     (Defaults to something)
    -V, --version    Prints version information";

#[test]
fn help_short() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_long() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_no_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
}

#[test]
fn help_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .subcommand(SubCommand::with_name("test")
            .about("tests things")
            .arg_from_usage("-v --verbose 'with verbosity'"))
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_short_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_long_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_help_rev() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "help", "subcmd"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn complex_help_output() {
    test::check_help(test::complex_app(), HELP);
}

#[test]
fn after_and_before_help_output() {
    let app = App::new("clap-test")
        .version("v1.4.8")
        .about("tests clap library")
        .before_help("some text that comes before the help")
        .after_help("some text that comes after the help");
    test::check_help(app, AFTER_HELP);
}

#[test]
fn multi_level_sc_help() {
    let app = App::new("ctest")
        .subcommand(SubCommand::with_name("subcmd")
            .subcommand(SubCommand::with_name("multi")
                .about("tests subcommands")
                .author("Kevin K. <kbknapp@gmail.com>")
                .version("0.1")
                .args_from_usage("
                    -f, --flag                    'tests flags'
                    -o, --option [scoption]...    'tests options'
                ")));
    test::check_err_output(app, "ctest help subcmd multi", MULTI_SC_HELP, false);
}

#[test]
fn no_wrap_help() {
    let app = App::new("ctest")
        .set_term_width(0)
        .help(MULTI_SC_HELP);
    test::check_err_output(app, "ctest --help", MULTI_SC_HELP, false);
}

#[test]
fn complex_subcommand_help_output() {
    let a = test::complex_app();
    test::check_subcommand_help(a, "subcmd", SC_HELP);
}

#[test]
fn issue_626_unicode_cutoff() {
    let app = App::new("ctest")
        .version("0.1")
        .set_term_width(70)
        .arg(Arg::with_name("cafe")
           .short("c")
           .long("cafe")
           .value_name("FILE")
           .help("A coffeehouse, coffee shop, or café is an establishment \
           which primarily serves hot coffee, related coffee beverages \
           (e.g., café latte, cappuccino, espresso), tea, and other hot \
           beverages. Some coffeehouses also serve cold beverages such as \
           iced coffee and iced tea. Many cafés also serve some type of \
           food, such as light snacks, muffins, or pastries.")
           .takes_value(true));
    test::check_err_output(app, "ctest --help", ISSUE_626_CUTOFF, false);
}

#[test]
fn hide_possible_vals() {
    let app = App::new("ctest")
        .version("0.1")
        .arg(Arg::with_name("pos")
           .short("p")
           .long("pos")
           .value_name("VAL")
           .possible_values(&["fast", "slow"])
           .help("Some vals")
           .takes_value(true))
        .arg(Arg::with_name("cafe")
           .short("c")
           .long("cafe")
           .value_name("FILE")
           .hide_possible_values(true)
           .possible_values(&["fast", "slow"])
           .help("A coffeehouse, coffee shop, or café.")
           .takes_value(true));
    test::check_err_output(app, "ctest --help", HIDE_POS_VALS, false);
}

#[test]
fn issue_626_panic() {
    let app = App::new("ctest")
        .version("0.1")
        .set_term_width(52)
        .arg(Arg::with_name("cafe")
           .short("c")
           .long("cafe")
           .value_name("FILE")
           .help("La culture du café est très développée dans de nombreux pays à climat chaud d'Amérique, \
           d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \
           Le café est souvent une contribution majeure aux exportations des régions productrices.")
           .takes_value(true));
    test::check_err_output(app, "ctest --help", ISSUE_626_PANIC, false);
}

#[test]
fn issue_626_variable_panic() {
    for i in 10..320 {
        let _ = App::new("ctest")
            .version("0.1")
            .set_term_width(i)
            .arg(Arg::with_name("cafe")
               .short("c")
               .long("cafe")
               .value_name("FILE")
               .help("La culture du café est très développée dans de nombreux pays à climat chaud d'Amérique, \
               d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \
               Le café est souvent une contribution majeure aux exportations des régions productrices.")
               .takes_value(true))
            .get_matches_from_safe(vec!["ctest", "--help"]);
    }
}

#[test]
fn old_newline_chars() {
    let app = App::new("ctest")
        .version("0.1")
        .arg(Arg::with_name("mode")
            .short("m")
            .help("Some help with some wrapping{n}(Defaults to something)"));
    test::check_err_output(app, "ctest --help", OLD_NEWLINE_CHARS, false);
}
<commit_msg>tests: adds tests to guard against issue-688<commit_after>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, AppSettings, SubCommand, ErrorKind, Arg};

static HELP: &'static str = "clap-test v1.4.8
Kevin K. <kbknapp@gmail.com>
tests clap library

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

FLAGS:
    -f, --flag       tests flags
    -F               tests flags with exclusions
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -O, --Option <option3>           specific vals [values: fast, slow]
        --long-option-2 <option2>    tests long options with exclusions
        --maxvals3 <maxvals>...      Tests 3 max vals
        --minvals2 <minvals>...      Tests 2 min vals
        --multvals <one> <two>       Tests mutliple values, not mult occs
        --multvalsmo <one> <two>     Tests mutliple values, and mult occs
    -o, --option <opt>...            tests options

ARGS:
    <positional>        tests positionals
    <positional2>       tests positionals with exclusions
    <positional3>...    tests specific values [values: vi, emacs]

SUBCOMMANDS:
    help      Prints this message or the help of the given subcommand(s)
    subcmd    tests subcommands";

static AFTER_HELP: &'static str = "some text that comes before the help

clap-test v1.4.8
tests clap library

USAGE:
    clap-test

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

some text that comes after the help";

static SC_HELP: &'static str = "subcmd 0.1
Kevin K. <kbknapp@gmail.com>
tests subcommands

USAGE:
    subcmd [FLAGS] [OPTIONS] [--] [scpositional]

FLAGS:
    -f, --flag    tests flags

OPTIONS:
    -o, --option <scoption>...    tests options

ARGS:
    <scpositional>    tests positionals";

static MULTI_SC_HELP: &'static str = "ctest-subcmd-multi 0.1
Kevin K. <kbknapp@gmail.com>
tests subcommands

USAGE:
    ctest subcmd multi [FLAGS] [OPTIONS]

FLAGS:
    -f, --flag       tests flags
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -o, --option <scoption>...    tests options";

static ISSUE_626_CUTOFF: &'static str = "ctest 0.1

USAGE:
    ctest [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -c, --cafe <FILE>    A coffeehouse, coffee shop, or café is an
                         establishment which primarily serves hot
                         coffee, related coffee beverages (e.g., café
                         latte, cappuccino, espresso), tea, and other
                         hot beverages. Some coffeehouses also serve
                         cold beverages such as iced coffee and iced
                         tea. Many cafés also serve some type of
                         food, such as light snacks, muffins, or
                         pastries.";

static ISSUE_626_PANIC: &'static str = "ctest 0.1

USAGE:
    ctest [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -c, --cafe <FILE>
            La culture du café est très développée
            dans de nombreux pays à climat chaud
            d\'Amérique, d\'Afrique et d\'Asie, dans
            des plantations qui sont cultivées pour
            les marchés d\'exportation. Le café est
            souvent une contribution majeure aux
            exportations des régions productrices.";

static HIDE_POS_VALS: &'static str = "ctest 0.1

USAGE:
    ctest [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -c, --cafe <FILE>    A coffeehouse, coffee shop, or café.
    -p, --pos <VAL>      Some vals [values: fast, slow]";

static OLD_NEWLINE_CHARS: &'static str = "ctest 0.1

USAGE:
    ctest [FLAGS]

FLAGS:
    -h, --help       Prints help information
    -m               Some help with some wrapping
                     (Defaults to something)
    -V, --version    Prints version information";

static ISSUE_688: &'static str = "ctest 0.1

USAGE:
    ctest [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
        --filter <filter>    Sets the filter, or sampling method, to use for interpolation when resizing the particle
                             images. The default is Linear (Bilinear). [values: Nearest, Linear, Cubic, Gaussian,
                             Lanczos3]";

#[test]
fn help_short() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_long() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_no_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
}

#[test]
fn help_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .subcommand(SubCommand::with_name("test")
            .about("tests things")
            .arg_from_usage("-v --verbose 'with verbosity'"))
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_short_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_long_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_help_rev() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "help", "subcmd"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn complex_help_output() {
    test::check_help(test::complex_app(), HELP);
}

#[test]
fn after_and_before_help_output() {
    let app = App::new("clap-test")
        .version("v1.4.8")
        .about("tests clap library")
        .before_help("some text that comes before the help")
        .after_help("some text that comes after the help");
    test::check_help(app, AFTER_HELP);
}

#[test]
fn multi_level_sc_help() {
    let app = App::new("ctest")
        .subcommand(SubCommand::with_name("subcmd")
            .subcommand(SubCommand::with_name("multi")
                .about("tests subcommands")
                .author("Kevin K. <kbknapp@gmail.com>")
                .version("0.1")
                .args_from_usage("
                    -f, --flag                    'tests flags'
                    -o, --option [scoption]...    'tests options'
                ")));
    test::check_err_output(app, "ctest help subcmd multi", MULTI_SC_HELP, false);
}

#[test]
fn no_wrap_help() {
    let app = App::new("ctest")
        .set_term_width(0)
        .help(MULTI_SC_HELP);
    test::check_err_output(app, "ctest --help", MULTI_SC_HELP, false);
}

#[test]
fn complex_subcommand_help_output() {
    let a = test::complex_app();
    test::check_subcommand_help(a, "subcmd", SC_HELP);
}

#[test]
fn issue_626_unicode_cutoff() {
    let app = App::new("ctest")
        .version("0.1")
        .set_term_width(70)
        .arg(Arg::with_name("cafe")
           .short("c")
           .long("cafe")
           .value_name("FILE")
           .help("A coffeehouse, coffee shop, or café is an establishment \
           which primarily serves hot coffee, related coffee beverages \
           (e.g., café latte, cappuccino, espresso), tea, and other hot \
           beverages. Some coffeehouses also serve cold beverages such as \
           iced coffee and iced tea. Many cafés also serve some type of \
           food, such as light snacks, muffins, or pastries.")
           .takes_value(true));
    test::check_err_output(app, "ctest --help", ISSUE_626_CUTOFF, false);
}

#[test]
fn hide_possible_vals() {
    let app = App::new("ctest")
        .version("0.1")
        .arg(Arg::with_name("pos")
           .short("p")
           .long("pos")
           .value_name("VAL")
           .possible_values(&["fast", "slow"])
           .help("Some vals")
           .takes_value(true))
        .arg(Arg::with_name("cafe")
           .short("c")
           .long("cafe")
           .value_name("FILE")
           .hide_possible_values(true)
           .possible_values(&["fast", "slow"])
           .help("A coffeehouse, coffee shop, or café.")
           .takes_value(true));
    test::check_err_output(app, "ctest --help", HIDE_POS_VALS, false);
}

#[test]
fn issue_626_panic() {
    let app = App::new("ctest")
        .version("0.1")
        .set_term_width(52)
        .arg(Arg::with_name("cafe")
           .short("c")
           .long("cafe")
           .value_name("FILE")
           .help("La culture du café est très développée dans de nombreux pays à climat chaud d'Amérique, \
           d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \
           Le café est souvent une contribution majeure aux exportations des régions productrices.")
           .takes_value(true));
    test::check_err_output(app, "ctest --help", ISSUE_626_PANIC, false);
}

#[test]
fn issue_626_variable_panic() {
    for i in 10..320 {
        let _ = App::new("ctest")
            .version("0.1")
            .set_term_width(i)
            .arg(Arg::with_name("cafe")
               .short("c")
               .long("cafe")
               .value_name("FILE")
               .help("La culture du café est très développée dans de nombreux pays à climat chaud d'Amérique, \
               d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \
               Le café est souvent une contribution majeure aux exportations des régions productrices.")
               .takes_value(true))
            .get_matches_from_safe(vec!["ctest", "--help"]);
    }
}

#[test]
fn old_newline_chars() {
    let app = App::new("ctest")
        .version("0.1")
        .arg(Arg::with_name("mode")
            .short("m")
            .help("Some help with some wrapping{n}(Defaults to something)"));
    test::check_err_output(app, "ctest --help", OLD_NEWLINE_CHARS, false);
}

#[test]
fn issue_688_hidden_pos_vals() {
	let filter_values = ["Nearest", "Linear", "Cubic", "Gaussian", "Lanczos3"];

	let app1 = App::new("ctest")
            .version("0.1")
			.set_term_width(120)
			.setting(AppSettings::HidePossibleValuesInHelp)
			.arg(Arg::with_name("filter")
				.help("Sets the filter, or sampling method, to use for interpolation when resizing the particle \
                images. The default is Linear (Bilinear). [values: Nearest, Linear, Cubic, Gaussian, Lanczos3]")
				.long("filter")
				.possible_values(&filter_values)
				.takes_value(true));
    test::check_err_output(app1, "ctest --help", ISSUE_688, false);

	let app2 = App::new("ctest")
            .version("0.1")
			.set_term_width(120)
			.arg(Arg::with_name("filter")
				.help("Sets the filter, or sampling method, to use for interpolation when resizing the particle \
                images. The default is Linear (Bilinear).")
				.long("filter")
				.possible_values(&filter_values)
				.takes_value(true));
    test::check_err_output(app2, "ctest --help", ISSUE_688, false);

	let app3 = App::new("ctest")
            .version("0.1")
			.set_term_width(120)
			.arg(Arg::with_name("filter")
				.help("Sets the filter, or sampling method, to use for interpolation when resizing the particle \
                images. The default is Linear (Bilinear). [values: Nearest, Linear, Cubic, Gaussian, Lanczos3]")
				.long("filter")
				.takes_value(true));
    test::check_err_output(app3, "ctest --help", ISSUE_688, false);
}<|endoftext|>


<commit_before>use crusty_chip::{decode, VirtualMachine, DISPLAY_HEIGHT, DISPLAY_WIDTH};
use getopts::Options;
use sfml::graphics::{RenderTarget, RenderWindow, Sprite, Texture, Transformable};
use sfml::system::Clock;
use sfml::window::{ContextSettings, Event, Style, VideoMode};
use std::fs::File;
use std::io::Read;

fn usage(progname: &str, opts: &Options) -> String {
    let brief = format!("{} rom_file", progname);
    format!("Usage: {}", opts.usage(&brief))
}

fn run() -> i32 {
    let mut args = std::env::args();
    let progname = args.next().expect("Missing program name?");
    let mut opts = Options::new();
    opts.optflag("", "pause", "Start in a paused state");

    let matches = match opts.parse(args) {
        Ok(matches) => matches,
        Err(e) => {
            eprintln!("{}\n\n{}", e, usage(&progname, &opts));
            return 1;
        }
    };

    let mut paused = matches.opt_present("pause");

    let filename = match matches.free.get(0) {
        Some(filename) => filename,
        None => {
            eprintln!("Required filename as first positional argument.\n");
            eprintln!("{}", usage(&progname, &opts));
            return 1;
        }
    };

    let mut clock = Clock::start();

    let mut file = match File::open(&filename) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Failed to open \"{}\": {}", filename, e);
            return 1;
        }
    };

    if file.metadata().unwrap().len() > crusty_chip::MEM_SIZE as u64 {
        eprintln!(
            "File \"{}\" is too big to be a proper CHIP-8 ROM.",
            filename
        );
        return 1;
    }

    let mut data = Vec::new();
    file.read_to_end(&mut data)
        .unwrap_or_else(|e| panic!("Failed to read rom: {}", e));

    let scale = 10;

    let mut ch8 = VirtualMachine::new();
    match ch8.load_rom(&data) {
        Ok(data) => data,
        Err(e) => {
            eprintln!("Error loading rom: \"{}\". Aborting.", e);
            return 1;
        }
    }

    let ctx = ContextSettings::default();
    let mut win = RenderWindow::new(
        VideoMode::new(
            DISPLAY_WIDTH as u32 * scale,
            DISPLAY_HEIGHT as u32 * scale,
            32,
        ),
        "CrustyChip",
        Style::CLOSE,
        &ctx,
    );
    win.set_vertical_sync_enabled(true);

    let mut tex = Texture::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32).unwrap();
    let mut saved_states = [None; 10];
    let mut printed_info = false;
    let mut cycles_made: u64 = 0;

    loop {
        let mut advance = false;
        while let Some(event) = win.poll_event() {
            use sfml::window::Key;
            fn key_mapping(code: Key) -> Option<u8> {
                match code {
                    Key::NUM1 => Some(1),
                    Key::NUM2 => Some(2),
                    Key::NUM3 => Some(3),
                    Key::NUM4 => Some(0xC),
                    Key::Q => Some(4),
                    Key::W => Some(5),
                    Key::E => Some(6),
                    Key::R => Some(0xD),
                    Key::A => Some(7),
                    Key::S => Some(8),
                    Key::D => Some(9),
                    Key::F => Some(0xE),
                    Key::Z => Some(0xA),
                    Key::X => Some(0),
                    Key::C => Some(0xB),
                    Key::V => Some(0xF),
                    _ => None,
                }
            }
            match event {
                Event::Closed => return 0,
                Event::KeyPressed {
                    code, ctrl, shift, ..
                } => {
                    if code == Key::P {
                        paused = !paused;
                    } else if code == Key::R && ctrl {
                        ch8 = VirtualMachine::new();
                        ch8.load_rom(&data).expect("ROM data too big? It changed?");
                    } else if code == Key::PERIOD {
                        advance = true;
                    } else if let Some(key) = key_mapping(code) {
                        ch8.press_key(key);
                    }
                    macro_rules! state_key (
                        ($s: expr, $k: ident) => (
                            if code == Key::$k {
                                if shift {
                                    saved_states[$s] = Some(ch8);
                                    eprintln!("Saved state {}.", $s);
                                } else if let Some(state) = saved_states[$s] {
                                    ch8 = state;
                                    eprintln!("Loaded state {}.", $s);
                                }
                            }
                        )
                    );
                    state_key!(0, F1);
                    state_key!(1, F2);
                    state_key!(2, F3);
                    state_key!(3, F4);
                    state_key!(4, F5);
                    state_key!(5, F6);
                    state_key!(6, F7);
                    state_key!(7, F8);
                    state_key!(8, F9);
                    state_key!(9, F10);
                }
                Event::KeyReleased { code, .. } => {
                    if let Some(key) = key_mapping(code) {
                        ch8.release_key(key);
                    }
                }
                _ => {}
            }
        }

        if clock.elapsed_time().as_seconds() >= 1.0 / 60.0 {
            ch8.decrement_timers();
            clock.restart();
        }

        if paused {
            std::thread::sleep(std::time::Duration::from_millis(25));
        }

        if paused && !printed_info {
            let raw_ins = ch8.get_ins();
            println!(
                "Cycle {}, pc @ {:#x}, ins: {:#x?} raw: {:#x}",
                cycles_made,
                ch8.pc(),
                decode(raw_ins),
                raw_ins
            );
            printed_info = true;
        }

        if !paused || advance {
            ch8.do_cycle();
            cycles_made += 1;
            printed_info = false;
        }

        let mut pixels = [255u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * 4];

        for (i, b) in ch8.display().iter().enumerate() {
            let idx = i * 4;
            if *b == 0u8 {
                for p in pixels[idx..idx + 3].iter_mut() {
                    *p = 0;
                }
            }
        }

        unsafe {
            tex.update_from_pixels(&pixels, DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32, 0, 0);
        }
        let mut sprite = Sprite::with_texture(&tex);
        sprite.set_scale((scale as f32, scale as f32));
        win.draw(&sprite);
        win.display();
    }
}

fn main() {
    std::process::exit(run());
}
<commit_msg>Remove pause sleep<commit_after>use crusty_chip::{decode, VirtualMachine, DISPLAY_HEIGHT, DISPLAY_WIDTH};
use getopts::Options;
use sfml::graphics::{RenderTarget, RenderWindow, Sprite, Texture, Transformable};
use sfml::system::Clock;
use sfml::window::{ContextSettings, Event, Style, VideoMode};
use std::fs::File;
use std::io::Read;

fn usage(progname: &str, opts: &Options) -> String {
    let brief = format!("{} rom_file", progname);
    format!("Usage: {}", opts.usage(&brief))
}

fn run() -> i32 {
    let mut args = std::env::args();
    let progname = args.next().expect("Missing program name?");
    let mut opts = Options::new();
    opts.optflag("", "pause", "Start in a paused state");

    let matches = match opts.parse(args) {
        Ok(matches) => matches,
        Err(e) => {
            eprintln!("{}\n\n{}", e, usage(&progname, &opts));
            return 1;
        }
    };

    let mut paused = matches.opt_present("pause");

    let filename = match matches.free.get(0) {
        Some(filename) => filename,
        None => {
            eprintln!("Required filename as first positional argument.\n");
            eprintln!("{}", usage(&progname, &opts));
            return 1;
        }
    };

    let mut clock = Clock::start();

    let mut file = match File::open(&filename) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Failed to open \"{}\": {}", filename, e);
            return 1;
        }
    };

    if file.metadata().unwrap().len() > crusty_chip::MEM_SIZE as u64 {
        eprintln!(
            "File \"{}\" is too big to be a proper CHIP-8 ROM.",
            filename
        );
        return 1;
    }

    let mut data = Vec::new();
    file.read_to_end(&mut data)
        .unwrap_or_else(|e| panic!("Failed to read rom: {}", e));

    let scale = 10;

    let mut ch8 = VirtualMachine::new();
    match ch8.load_rom(&data) {
        Ok(data) => data,
        Err(e) => {
            eprintln!("Error loading rom: \"{}\". Aborting.", e);
            return 1;
        }
    }

    let ctx = ContextSettings::default();
    let mut win = RenderWindow::new(
        VideoMode::new(
            DISPLAY_WIDTH as u32 * scale,
            DISPLAY_HEIGHT as u32 * scale,
            32,
        ),
        "CrustyChip",
        Style::CLOSE,
        &ctx,
    );
    win.set_vertical_sync_enabled(true);

    let mut tex = Texture::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32).unwrap();
    let mut saved_states = [None; 10];
    let mut printed_info = false;
    let mut cycles_made: u64 = 0;

    loop {
        let mut advance = false;
        while let Some(event) = win.poll_event() {
            use sfml::window::Key;
            fn key_mapping(code: Key) -> Option<u8> {
                match code {
                    Key::NUM1 => Some(1),
                    Key::NUM2 => Some(2),
                    Key::NUM3 => Some(3),
                    Key::NUM4 => Some(0xC),
                    Key::Q => Some(4),
                    Key::W => Some(5),
                    Key::E => Some(6),
                    Key::R => Some(0xD),
                    Key::A => Some(7),
                    Key::S => Some(8),
                    Key::D => Some(9),
                    Key::F => Some(0xE),
                    Key::Z => Some(0xA),
                    Key::X => Some(0),
                    Key::C => Some(0xB),
                    Key::V => Some(0xF),
                    _ => None,
                }
            }
            match event {
                Event::Closed => return 0,
                Event::KeyPressed {
                    code, ctrl, shift, ..
                } => {
                    if code == Key::P {
                        paused = !paused;
                    } else if code == Key::R && ctrl {
                        ch8 = VirtualMachine::new();
                        ch8.load_rom(&data).expect("ROM data too big? It changed?");
                    } else if code == Key::PERIOD {
                        advance = true;
                    } else if let Some(key) = key_mapping(code) {
                        ch8.press_key(key);
                    }
                    macro_rules! state_key (
                        ($s: expr, $k: ident) => (
                            if code == Key::$k {
                                if shift {
                                    saved_states[$s] = Some(ch8);
                                    eprintln!("Saved state {}.", $s);
                                } else if let Some(state) = saved_states[$s] {
                                    ch8 = state;
                                    eprintln!("Loaded state {}.", $s);
                                }
                            }
                        )
                    );
                    state_key!(0, F1);
                    state_key!(1, F2);
                    state_key!(2, F3);
                    state_key!(3, F4);
                    state_key!(4, F5);
                    state_key!(5, F6);
                    state_key!(6, F7);
                    state_key!(7, F8);
                    state_key!(8, F9);
                    state_key!(9, F10);
                }
                Event::KeyReleased { code, .. } => {
                    if let Some(key) = key_mapping(code) {
                        ch8.release_key(key);
                    }
                }
                _ => {}
            }
        }

        if clock.elapsed_time().as_seconds() >= 1.0 / 60.0 {
            ch8.decrement_timers();
            clock.restart();
        }

        if paused && !printed_info {
            let raw_ins = ch8.get_ins();
            println!(
                "Cycle {}, pc @ {:#x}, ins: {:#x?} raw: {:#x}",
                cycles_made,
                ch8.pc(),
                decode(raw_ins),
                raw_ins
            );
            printed_info = true;
        }

        if !paused || advance {
            ch8.do_cycle();
            cycles_made += 1;
            printed_info = false;
        }

        let mut pixels = [255u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * 4];

        for (i, b) in ch8.display().iter().enumerate() {
            let idx = i * 4;
            if *b == 0u8 {
                for p in pixels[idx..idx + 3].iter_mut() {
                    *p = 0;
                }
            }
        }

        unsafe {
            tex.update_from_pixels(&pixels, DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32, 0, 0);
        }
        let mut sprite = Sprite::with_texture(&tex);
        sprite.set_scale((scale as f32, scale as f32));
        win.draw(&sprite);
        win.display();
    }
}

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


<commit_before>use types::{Hash256}
use hashing::canonical_hash;

fn merkle_root(values: Vec<T>) -> Hash256 {
    let mut o = vec![0; values.len()];
    o.append(values);

    for v in &values {
        canonical_hash(v.as_bytes());
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn calculate_merkle_root() {
        let values = vec!['abc', 'lmn', 'xyz', 'o0o'];

        let test_leaf_1 = canonical_hash(values[0]);
        let test_leaf_2 = canonical_hash(values[1]);
        let test_leaf_3 = canonical_hash(values[2]);
        let test_leaf_4 = canonical_hash(values[3]);
        let test_node_1 = canonical_hash(vec![test_leaf_4, test_leaf_3]);
        let test_node_2 = canonical_hash(vec![test_leaf_2, test_leaf_1]);
        let test_root   = canonical_hash(vec![test_node_1, test_node_2]);

        let result      = merkle_root(values);
        assert_eq!(result, test_root);
    }
}
<commit_msg>fix(hashing): reverse loop #146<commit_after>use types::{Hash256}
use hashing::canonical_hash;
use std::iter::range_step;

fn merkle_root(values: Vec<T>) -> Hash256 {
    let mut o = vec![0; values.len()];
    o.append(values);

    for v in range_step(values - 1, 0, -1) {
        canonical_hash(v.as_bytes());
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn calculate_merkle_root() {
        let values = vec!['abc', 'lmn', 'xyz', 'o0o'];

        let test_leaf_1 = canonical_hash(values[0]);
        let test_leaf_2 = canonical_hash(values[1]);
        let test_leaf_3 = canonical_hash(values[2]);
        let test_leaf_4 = canonical_hash(values[3]);
        let test_node_1 = canonical_hash(vec![test_leaf_4, test_leaf_3]);
        let test_node_2 = canonical_hash(vec![test_leaf_2, test_leaf_1]);
        let test_root   = canonical_hash(vec![test_node_1, test_node_2]);

        let result      = merkle_root(values);
        assert_eq!(result, test_root);
    }
}
<|endoftext|>