<commit_before>pub struct Trie {
    vec: Vec<(char, Box<Trie>)>,
    word: bool,
}

impl Trie {
    pub fn new() -> Trie {
        Trie {
            vec: vec![],
            word: false,
        }
    }

    pub fn clear(&mut self) {
        self.vec.clear();
        self.word = false;
    }

    pub fn insert(&mut self, str: &str) {
        let mut trie_ptr: *mut Trie = &mut *self;
        for char in str.chars() {
            trie_ptr = get_char_node_for_insert(trie_ptr, char);
        }

        unsafe {
            (*trie_ptr).word = true;
        }
    }

    pub fn contains(&self, str: &str) -> bool {
        let mut trie = self;
        for char in str.chars() {
            if let Some(trie_) = get_char_node_for_lookup(trie, char) {
                trie = trie_;
            } else {
                return false;
            }
        }
        trie.word
    }

    // TODO: This needs garbage collection. We may want to trim the branches
    // that doesn't have any words.
    pub fn remove(&mut self, str: &str) {
        let mut chars = str.chars();
        if let Some(char) = chars.next() {
            if let Ok(idx) = self.vec.binary_search_by(|&(char_, _)| char_.cmp(&char)) {
                self.vec[idx].1.remove(chars.as_str());
            }
        } else {
            self.word = false;
        }
    }

    // TODO: We need an Iterator instance instead.
    pub fn to_strings(&self, prefix: &str) -> Vec<String> {
        let mut ret = {
            if self.word {
                vec![prefix.to_owned()]
            } else {
                vec![]
            }
        };

        for &(c, ref t) in &self.vec {
            let mut prefix_ = prefix.to_owned();
            prefix_.push(c);
            ret.extend_from_slice(&t.to_strings(&prefix_));
        }

        ret
    }

    // TODO: We need an Iterator instance instead.
    pub fn drop_pfx(&self, prefix: &mut Iterator<Item = char>) -> Vec<String> {
        let mut trie = self;
        for char in prefix {
            if let Some(trie_) = get_char_node_for_lookup(trie, char) {
                trie = trie_;
            } else {
                return vec![];
            }
        }
        trie.to_strings("")
    }
}

fn get_char_node_for_insert(trie: *mut Trie, char: char) -> *mut Trie {
    let trie_ref: &mut Trie = unsafe { &mut *trie };
    match trie_ref
        .vec
        .binary_search_by(|&(char_, _)| char_.cmp(&char))
    {
        Ok(idx) =>
            &mut *trie_ref.vec[idx].1,
        Err(idx) => {
            trie_ref.vec.insert(
                idx,
                (
                    char,
                    Box::new(Trie {
                        vec: vec![],
                        word: false,
                    }),
                ),
            );
            &mut *trie_ref.vec[idx].1
        }
    }
}

fn get_char_node_for_lookup(trie: &Trie, char: char) -> Option<&Trie> {
    match trie.vec.binary_search_by(|&(char_, _)| char_.cmp(&char)) {
        Ok(idx) =>
            Some(&trie.vec[idx].1),
        Err(_) =>
            None,
    }
}

#[cfg(test)]
mod tests {

    extern crate test;

    use super::*;

    #[test]
    fn trie_test_1() {
        let mut trie = Trie::new();
        trie.insert("yada yada");
        assert_eq!(vec!["yada yada"], trie.to_strings(""));
    }

    #[test]
    fn trie_test_2() {
        let mut trie = Trie::new();
        trie.insert("foo");
        assert!(trie.contains("foo"));
        trie.insert("bar");
        assert!(trie.contains("foo"));
        assert!(trie.contains("bar"));
        trie.insert("baz");
        assert!(trie.contains("foo"));
        assert!(trie.contains("bar"));
        assert!(trie.contains("baz"));
        assert_eq!(vec!["bar", "baz", "foo"], trie.to_strings(""));
    }

    #[test]
    fn trie_test_3() {
        let mut trie = Trie::new();
        trie.insert("foo");
        trie.insert("bar");
        trie.insert("baz");
        assert_eq!(vec!["ar", "az"], trie.drop_pfx(&mut "b".chars()));
    }

    #[test]
    fn trie_test_insert_remove() {
        let mut trie = Trie::new();
        trie.insert("foo");
        trie.insert("bar");
        trie.insert("baz");
        trie.remove("bar");
        assert!(trie.contains("foo"));
        assert!(!trie.contains("bar"));
        assert!(trie.contains("baz"));
        assert_eq!(vec!["az"], trie.drop_pfx(&mut "b".chars()));
    }

} // tests

#[cfg(test)]
mod benchs {

    extern crate test;

    use self::test::Bencher;
    use std::fs::File;
    use std::io::Read;
    use super::*;

    #[bench]
    fn bench_trie_build(b: &mut Bencher) {
        // Total words: 305,089
        // 117,701,680 ns (0.1 seconds)
        // (before reversing the list: 116,795,268 ns (0.1 seconds))

        let mut contents = String::new();
        let mut words: Vec<&str> = vec![];
        {
            match File::open("/usr/share/dict/american") {
                Err(_) => {
                    println!("Can't open dictionary file, aborting benchmark.");
                    return;
                }
                Ok(mut file) => {
                    file.read_to_string(&mut contents).unwrap();
                    words.extend(contents.lines());
                }
            }
        }

        b.iter(|| {
            let mut trie = Trie::new();
            // Note that we insert the words in reverse order here. Since the
            // dictionary is already sorted, we end up benchmarking the best case.
            // Since that best case is never really happens in practice, the number
            // is practically useless. Worst case is at least giving an upper bound.
            for word in words.iter().rev() {
                trie.insert(word);
            }
            trie
        });
    }

    /*
#[bench]
fn bench_hashset_build(b : &mut Bencher) {

    // Total words: 305,089
    // 40,292,006 ns (0.04 seconds)

    use std::collections::HashSet;

    let mut contents = String::new();
    let mut words : Vec<&str> = vec![];
    {
        let mut file = File::open("/usr/share/dict/american").unwrap();
        file.read_to_string(&mut contents).unwrap();
        words.extend(contents.lines());
    }

    b.iter(|| {
        let mut set = HashSet::new();
        for word in words.iter() {
            set.insert(word);
        }
        set
    });
}
*/

    #[bench]
    fn bench_trie_lookup(b: &mut Bencher) {
        // Total:     305,089 words
        // Returning:     235 words
        // 140,717 ns (0.14 ms)

        let mut contents = String::new();
        let mut words: Vec<&str> = vec![];
        {
            match File::open("/usr/share/dict/american") {
                Err(_) => {
                    println!("Can't open dictionary file, aborting benchmark.");
                    return;
                }
                Ok(mut file) => {
                    file.read_to_string(&mut contents).unwrap();
                    words.extend(contents.lines());
                }
            }
        }

        let mut trie = Trie::new();
        for word in words {
            trie.insert(word);
        }

        b.iter(|| trie.drop_pfx(&mut "abs".chars()));
    }

    #[bench]
    fn bench_trie_list_all(b: &mut Bencher) {
        // Total:     305,089 words
        // Returning: 305,089 words
        // 205,946,060 ns (0.2 s)

        let mut contents = String::new();
        let mut words: Vec<&str> = vec![];
        {
            match File::open("/usr/share/dict/american") {
                Err(_) => {
                    println!("Can't open dictionary file, aborting benchmark.");
                    return;
                }
                Ok(mut file) => {
                    file.read_to_string(&mut contents).unwrap();
                    words.extend(contents.lines());
                }
            }
        }

        let mut trie = Trie::new();
        for word in words {
            trie.insert(word);
        }

        b.iter(|| trie.drop_pfx(&mut "".chars()));
    }

} // benchs
<commit_msg>Avoid unnecessary clone of Vec<commit_after>pub struct Trie {
    vec: Vec<(char, Box<Trie>)>,
    word: bool,
}

impl Trie {
    pub fn new() -> Trie {
        Trie {
            vec: vec![],
            word: false,
        }
    }

    pub fn clear(&mut self) {
        self.vec.clear();
        self.word = false;
    }

    pub fn insert(&mut self, str: &str) {
        let mut trie_ptr: *mut Trie = &mut *self;
        for char in str.chars() {
            trie_ptr = get_char_node_for_insert(trie_ptr, char);
        }

        unsafe {
            (*trie_ptr).word = true;
        }
    }

    pub fn contains(&self, str: &str) -> bool {
        let mut trie = self;
        for char in str.chars() {
            if let Some(trie_) = get_char_node_for_lookup(trie, char) {
                trie = trie_;
            } else {
                return false;
            }
        }
        trie.word
    }

    // TODO: This needs garbage collection. We may want to trim the branches
    // that doesn't have any words.
    pub fn remove(&mut self, str: &str) {
        let mut chars = str.chars();
        if let Some(char) = chars.next() {
            if let Ok(idx) = self.vec.binary_search_by(|&(char_, _)| char_.cmp(&char)) {
                self.vec[idx].1.remove(chars.as_str());
            }
        } else {
            self.word = false;
        }
    }

    // TODO: We need an Iterator instance instead.
    pub fn to_strings(&self, prefix: &str) -> Vec<String> {
        let mut ret = {
            if self.word {
                vec![prefix.to_owned()]
            } else {
                vec![]
            }
        };

        for &(c, ref t) in &self.vec {
            let mut prefix_ = prefix.to_owned();
            prefix_.push(c);
            ret.extend(t.to_strings(&prefix_));
        }

        ret
    }

    // TODO: We need an Iterator instance instead.
    pub fn drop_pfx(&self, prefix: &mut Iterator<Item = char>) -> Vec<String> {
        let mut trie = self;
        for char in prefix {
            if let Some(trie_) = get_char_node_for_lookup(trie, char) {
                trie = trie_;
            } else {
                return vec![];
            }
        }
        trie.to_strings("")
    }
}

fn get_char_node_for_insert(trie: *mut Trie, char: char) -> *mut Trie {
    let trie_ref: &mut Trie = unsafe { &mut *trie };
    match trie_ref
        .vec
        .binary_search_by(|&(char_, _)| char_.cmp(&char))
    {
        Ok(idx) =>
            &mut *trie_ref.vec[idx].1,
        Err(idx) => {
            trie_ref.vec.insert(
                idx,
                (
                    char,
                    Box::new(Trie {
                        vec: vec![],
                        word: false,
                    }),
                ),
            );
            &mut *trie_ref.vec[idx].1
        }
    }
}

fn get_char_node_for_lookup(trie: &Trie, char: char) -> Option<&Trie> {
    match trie.vec.binary_search_by(|&(char_, _)| char_.cmp(&char)) {
        Ok(idx) =>
            Some(&trie.vec[idx].1),
        Err(_) =>
            None,
    }
}

#[cfg(test)]
mod tests {

    extern crate test;

    use super::*;

    #[test]
    fn trie_test_1() {
        let mut trie = Trie::new();
        trie.insert("yada yada");
        assert_eq!(vec!["yada yada"], trie.to_strings(""));
    }

    #[test]
    fn trie_test_2() {
        let mut trie = Trie::new();
        trie.insert("foo");
        assert!(trie.contains("foo"));
        trie.insert("bar");
        assert!(trie.contains("foo"));
        assert!(trie.contains("bar"));
        trie.insert("baz");
        assert!(trie.contains("foo"));
        assert!(trie.contains("bar"));
        assert!(trie.contains("baz"));
        assert_eq!(vec!["bar", "baz", "foo"], trie.to_strings(""));
    }

    #[test]
    fn trie_test_3() {
        let mut trie = Trie::new();
        trie.insert("foo");
        trie.insert("bar");
        trie.insert("baz");
        assert_eq!(vec!["ar", "az"], trie.drop_pfx(&mut "b".chars()));
    }

    #[test]
    fn trie_test_insert_remove() {
        let mut trie = Trie::new();
        trie.insert("foo");
        trie.insert("bar");
        trie.insert("baz");
        trie.remove("bar");
        assert!(trie.contains("foo"));
        assert!(!trie.contains("bar"));
        assert!(trie.contains("baz"));
        assert_eq!(vec!["az"], trie.drop_pfx(&mut "b".chars()));
    }

} // tests

#[cfg(test)]
mod benchs {

    extern crate test;

    use self::test::Bencher;
    use std::fs::File;
    use std::io::Read;
    use super::*;

    #[bench]
    fn bench_trie_build(b: &mut Bencher) {
        // Total words: 305,089
        // 117,701,680 ns (0.1 seconds)
        // (before reversing the list: 116,795,268 ns (0.1 seconds))

        let mut contents = String::new();
        let mut words: Vec<&str> = vec![];
        {
            match File::open("/usr/share/dict/american") {
                Err(_) => {
                    println!("Can't open dictionary file, aborting benchmark.");
                    return;
                }
                Ok(mut file) => {
                    file.read_to_string(&mut contents).unwrap();
                    words.extend(contents.lines());
                }
            }
        }

        b.iter(|| {
            let mut trie = Trie::new();
            // Note that we insert the words in reverse order here. Since the
            // dictionary is already sorted, we end up benchmarking the best case.
            // Since that best case is never really happens in practice, the number
            // is practically useless. Worst case is at least giving an upper bound.
            for word in words.iter().rev() {
                trie.insert(word);
            }
            trie
        });
    }

    /*
#[bench]
fn bench_hashset_build(b : &mut Bencher) {

    // Total words: 305,089
    // 40,292,006 ns (0.04 seconds)

    use std::collections::HashSet;

    let mut contents = String::new();
    let mut words : Vec<&str> = vec![];
    {
        let mut file = File::open("/usr/share/dict/american").unwrap();
        file.read_to_string(&mut contents).unwrap();
        words.extend(contents.lines());
    }

    b.iter(|| {
        let mut set = HashSet::new();
        for word in words.iter() {
            set.insert(word);
        }
        set
    });
}
*/

    #[bench]
    fn bench_trie_lookup(b: &mut Bencher) {
        // Total:     305,089 words
        // Returning:     235 words
        // 140,717 ns (0.14 ms)

        let mut contents = String::new();
        let mut words: Vec<&str> = vec![];
        {
            match File::open("/usr/share/dict/american") {
                Err(_) => {
                    println!("Can't open dictionary file, aborting benchmark.");
                    return;
                }
                Ok(mut file) => {
                    file.read_to_string(&mut contents).unwrap();
                    words.extend(contents.lines());
                }
            }
        }

        let mut trie = Trie::new();
        for word in words {
            trie.insert(word);
        }

        b.iter(|| trie.drop_pfx(&mut "abs".chars()));
    }

    #[bench]
    fn bench_trie_list_all(b: &mut Bencher) {
        // Total:     305,089 words
        // Returning: 305,089 words
        // 205,946,060 ns (0.2 s)

        let mut contents = String::new();
        let mut words: Vec<&str> = vec![];
        {
            match File::open("/usr/share/dict/american") {
                Err(_) => {
                    println!("Can't open dictionary file, aborting benchmark.");
                    return;
                }
                Ok(mut file) => {
                    file.read_to_string(&mut contents).unwrap();
                    words.extend(contents.lines());
                }
            }
        }

        let mut trie = Trie::new();
        for word in words {
            trie.insert(word);
        }

        b.iter(|| trie.drop_pfx(&mut "".chars()));
    }

} // benchs
<|endoftext|>


<commit_before>use rustc::hir::*;
use rustc::hir::intravisit::FnKind;
use rustc::hir::def_id::DefId;
use rustc::lint::*;
use rustc::ty;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use syntax::ast::NodeId;
use syntax_pos::Span;
use utils::{in_macro, is_self, is_copy, implements_trait, get_trait_def_id, snippet, span_lint_and_then, paths};
use std::collections::HashSet;

/// **What it does:** Checks for functions taking arguments by value, but only using them by
/// reference.
///
/// **Why is this bad?**
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
/// ```rust
/// fn foo(v: Vec<i32>) {
///     assert_eq!(v.len(), 42);
/// }
/// ```
declare_lint! {
    pub NEEDLESS_TAKE_BY_VALUE,
    Warn,
    "taking arguments by value, but only using them by reference"
}

pub struct NeedlessTakeByValue;

impl LintPass for NeedlessTakeByValue {
    fn get_lints(&self) -> LintArray {
        lint_array![NEEDLESS_TAKE_BY_VALUE]
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessTakeByValue {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        node_id: NodeId
    ) {
        if in_macro(cx, span) {
            return;
        }

        if let FnKind::ItemFn(..) = kind {
        } else {
            return;
        }

        // These are usually took by value and only used by reference
        let fn_trait = cx.tcx.lang_items.fn_trait().expect("failed to find `Fn` trait");
        let asref_trait = get_trait_def_id(cx, &paths::ASREF_TRAIT).expect("failed to find `AsRef` trait");
        let borrow_trait = get_trait_def_id(cx, &paths::BORROW_TRAIT).expect("failed to find `Borrow` trait");

        // Collect moved variables from the function body
        let moved_vars = {
            let mut ctx = MovedVariablesCtxt::new(cx);
            let infcx = cx.tcx.borrowck_fake_infer_ctxt(body.id());
            {
                let mut v = euv::ExprUseVisitor::new(&mut ctx, &infcx);
                v.consume_body(body);
            }
            ctx.moved_vars
        };

        let fn_def_id = cx.tcx.hir.local_def_id(node_id);
        let param_env = ty::ParameterEnvironment::for_item(cx.tcx, node_id);
        let fn_sig = cx.tcx.item_type(fn_def_id).fn_sig();
        let fn_sig = cx.tcx.liberate_late_bound_regions(param_env.free_id_outlive, fn_sig);

        for ((input, ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments) {
            if_let_chain! {[
                !is_self(arg),
                !ty.is_mutable_pointer(),
                !is_copy(cx, ty, node_id),
                !implements_trait(cx, ty, fn_trait, &[], Some(node_id)),
                !implements_trait(cx, ty, asref_trait, &[], Some(node_id)),
                !implements_trait(cx, ty, borrow_trait, &[], Some(node_id)),

                let PatKind::Binding(mode, defid, ..) = arg.pat.node,
                !moved_vars.contains(&defid),
            ], {
                // Note: `toplevel_ref_arg` warns if `BindByRef`
                let m = match mode {
                    BindingMode::BindByRef(m) | BindingMode::BindByValue(m) => m,
                };
                if m == Mutability::MutMutable {
                    continue;
                }

                span_lint_and_then(cx,
                          NEEDLESS_TAKE_BY_VALUE,
                          input.span,
                          "this function taking a value by value, but only using them by reference",
                          |db| {
                              db.span_suggestion(input.span,
                                                 "consider taking a reference instead",
                                                 format!("&{}", snippet(cx, input.span, "_")));
                          });
            }}
        }
    }
}

struct MovedVariablesCtxt<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    moved_vars: HashSet<DefId>,
}

impl<'a, 'tcx: 'a> MovedVariablesCtxt<'a, 'tcx> {
    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        MovedVariablesCtxt {
            cx: cx,
            moved_vars: HashSet::new(),
        }
    }

    fn consume_common(
        &mut self,
        _consume_id: NodeId,
        _consume_span: Span,
        cmt: mc::cmt<'tcx>,
        mode: euv::ConsumeMode
    ) {
        if_let_chain! {[
            let euv::ConsumeMode::Move(_) = mode,
            let mc::Categorization::Local(vid) = cmt.cat,
        ], {
            if let Some(def_id) = self.cx.tcx.hir.opt_local_def_id(vid) {
                self.moved_vars.insert(def_id);
            }
        }}

    }
}

impl<'a, 'tcx: 'a> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
    fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        self.consume_common(consume_id, consume_span, cmt, mode);
    }

    fn matched_pat(&mut self, _matched_pat: &Pat, _cmt: mc::cmt, _mode: euv::MatchMode) {}

    fn consume_pat(&mut self, consume_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        self.consume_common(consume_pat.id, consume_pat.span, cmt, mode);
    }

    fn borrow(
        &mut self,
        _borrow_id: NodeId,
        _borrow_span: Span,
        _cmt: mc::cmt<'tcx>,
        _loan_region: &'tcx ty::Region,
        _bk: ty::BorrowKind,
        _loan_cause: euv::LoanCause
    ) {
    }

    fn mutate(
        &mut self,
        _assignment_id: NodeId,
        _assignment_span: Span,
        _assignee_cmt: mc::cmt<'tcx>,
        _mode: euv::MutateMode
    ) {
    }

    fn decl_without_init(&mut self, _id: NodeId, _span: Span) {}
}
<commit_msg>Add explanation<commit_after>use rustc::hir::*;
use rustc::hir::intravisit::FnKind;
use rustc::hir::def_id::DefId;
use rustc::lint::*;
use rustc::ty;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use syntax::ast::NodeId;
use syntax_pos::Span;
use utils::{in_macro, is_self, is_copy, implements_trait, get_trait_def_id, snippet, span_lint_and_then, paths};
use std::collections::HashSet;

/// **What it does:** Checks for functions taking arguments by value, but only using them by
/// reference.
///
/// **Why is this bad?** In such cases, taking arguments by reference is more flexible and
/// can sometimes avoid unnecessary allocations.
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
/// ```rust
/// fn foo(v: Vec<i32>) {
///     assert_eq!(v.len(), 42);
/// }
/// ```
declare_lint! {
    pub NEEDLESS_TAKE_BY_VALUE,
    Warn,
    "taking arguments by value, but only using them by reference"
}

pub struct NeedlessTakeByValue;

impl LintPass for NeedlessTakeByValue {
    fn get_lints(&self) -> LintArray {
        lint_array![NEEDLESS_TAKE_BY_VALUE]
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessTakeByValue {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        node_id: NodeId
    ) {
        if in_macro(cx, span) {
            return;
        }

        if let FnKind::ItemFn(..) = kind {
        } else {
            return;
        }

        // These are usually took by value and only used by reference
        let fn_trait = cx.tcx.lang_items.fn_trait().expect("failed to find `Fn` trait");
        let asref_trait = get_trait_def_id(cx, &paths::ASREF_TRAIT).expect("failed to find `AsRef` trait");
        let borrow_trait = get_trait_def_id(cx, &paths::BORROW_TRAIT).expect("failed to find `Borrow` trait");

        // Collect moved variables from the function body
        let moved_vars = {
            let mut ctx = MovedVariablesCtxt::new(cx);
            let infcx = cx.tcx.borrowck_fake_infer_ctxt(body.id());
            {
                let mut v = euv::ExprUseVisitor::new(&mut ctx, &infcx);
                v.consume_body(body);
            }
            ctx.moved_vars
        };

        let fn_def_id = cx.tcx.hir.local_def_id(node_id);
        let param_env = ty::ParameterEnvironment::for_item(cx.tcx, node_id);
        let fn_sig = cx.tcx.item_type(fn_def_id).fn_sig();
        let fn_sig = cx.tcx.liberate_late_bound_regions(param_env.free_id_outlive, fn_sig);

        for ((input, ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments) {
            if_let_chain! {[
                !is_self(arg),
                !ty.is_mutable_pointer(),
                !is_copy(cx, ty, node_id),
                !implements_trait(cx, ty, fn_trait, &[], Some(node_id)),
                !implements_trait(cx, ty, asref_trait, &[], Some(node_id)),
                !implements_trait(cx, ty, borrow_trait, &[], Some(node_id)),

                let PatKind::Binding(mode, defid, ..) = arg.pat.node,
                !moved_vars.contains(&defid),
            ], {
                // Note: `toplevel_ref_arg` warns if `BindByRef`
                let m = match mode {
                    BindingMode::BindByRef(m) | BindingMode::BindByValue(m) => m,
                };
                if m == Mutability::MutMutable {
                    continue;
                }

                span_lint_and_then(cx,
                          NEEDLESS_TAKE_BY_VALUE,
                          input.span,
                          "this function taking a value by value, but only using them by reference",
                          |db| {
                              db.span_suggestion(input.span,
                                                 "consider taking a reference instead",
                                                 format!("&{}", snippet(cx, input.span, "_")));
                          });
            }}
        }
    }
}

struct MovedVariablesCtxt<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    moved_vars: HashSet<DefId>,
}

impl<'a, 'tcx: 'a> MovedVariablesCtxt<'a, 'tcx> {
    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        MovedVariablesCtxt {
            cx: cx,
            moved_vars: HashSet::new(),
        }
    }

    fn consume_common(
        &mut self,
        _consume_id: NodeId,
        _consume_span: Span,
        cmt: mc::cmt<'tcx>,
        mode: euv::ConsumeMode
    ) {
        if_let_chain! {[
            let euv::ConsumeMode::Move(_) = mode,
            let mc::Categorization::Local(vid) = cmt.cat,
        ], {
            if let Some(def_id) = self.cx.tcx.hir.opt_local_def_id(vid) {
                self.moved_vars.insert(def_id);
            }
        }}

    }
}

impl<'a, 'tcx: 'a> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
    fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        self.consume_common(consume_id, consume_span, cmt, mode);
    }

    fn matched_pat(&mut self, _matched_pat: &Pat, _cmt: mc::cmt, _mode: euv::MatchMode) {}

    fn consume_pat(&mut self, consume_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        self.consume_common(consume_pat.id, consume_pat.span, cmt, mode);
    }

    fn borrow(
        &mut self,
        _borrow_id: NodeId,
        _borrow_span: Span,
        _cmt: mc::cmt<'tcx>,
        _loan_region: &'tcx ty::Region,
        _bk: ty::BorrowKind,
        _loan_cause: euv::LoanCause
    ) {
    }

    fn mutate(
        &mut self,
        _assignment_id: NodeId,
        _assignment_span: Span,
        _assignee_cmt: mc::cmt<'tcx>,
        _mode: euv::MutateMode
    ) {
    }

    fn decl_without_init(&mut self, _id: NodeId, _span: Span) {}
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::env::args;
use std::io::prelude::*;
use std::path::Path;
use std::io::stdout;
use std::u8;
use std::string::ToString;

// impl IntoUrl for SocketAddr {
//
// }

// for now this only will work with kde neon
pub fn load_linux_dictionary() -> Option<Vec<String>> {
    match File::open("/etc/dictionaries-common/words") {
        Ok(mut file) => {
            let mut output: Vec<String> = vec![];
            let mut buffer = String::new();
            match file.read_to_string(&mut buffer) {
                Ok(_) => {
                    Some(buffer.split("\n")
                        .map(|x| x.to_string())
                        .collect())
                }
                Err(_) => None,
            }
        }
        Err(_) => None,
    }
}

pub fn u8_vector(amount: u8) -> Vec<u8> {
    let mut v: Vec<u8> = vec![];

    for i in 0..amount {
        v.push(0);
    }

    v
}

pub fn read_r4c_file(arg: String) -> Option<Vec<u8>> {
    let mut output: Vec<u8> = vec![];
    let mut file = File::open(arg).unwrap();
    let mut buf = String::new();
    file.read_to_string(&mut buf);

    let mut count = 0;
    let mut tmp = 0;

    for ch in buf.chars() {
        let s = ch.to_string();
        let u4 = u8::from_str_radix(&s, 16).unwrap();
        if count % 2 == 0 {
            // output.push(u4);
            tmp = u4 << 4;
        } else {
            let back = tmp | u4;
            output.push(back);
        }
        count = count + 1;
    }

    Some(output)
}

pub fn read_file_from_arg(arg: Option<String>) -> Option<Vec<u8>> {
    match arg {
        Some(name) => {
            match File::open(name) {
                Ok(mut file) => {
                    let mut output: Vec<u8> = vec![];
                    match file.read_to_end(&mut output) {
                        Ok(_) => Some(output),
                        Err(_) => None,
                    }
                }
                Err(_) => None,
            }
        }
        None => None,
    }
}

// remember to add some stuff here...
// we could use the english dictionary supplied with every linux distro....
// maybe different for mac's and pc's
pub fn is_english(plain_text: String) -> bool {
    true
}

pub fn prompt(s: &str) {
    print!("{}", s);
    stdout().flush();
}
<commit_msg>remove trailing new line<commit_after>use std::fs::File;
use std::env::args;
use std::io::prelude::*;
use std::path::Path;
use std::io::stdout;
use std::u8;
use std::string::ToString;

// impl IntoUrl for SocketAddr {
//
// }

// for now this only will work with kde neon
pub fn load_linux_dictionary() -> Option<Vec<String>> {
    match File::open("/etc/dictionaries-common/words") {
        Ok(mut file) => {
            let mut output: Vec<String> = vec![];
            let mut buffer = String::new();
            match file.read_to_string(&mut buffer) {
                Ok(_) => {
                    Some(buffer.split("\n")
                        .map(|x| x.to_string())
                        .collect())
                }
                Err(_) => None,
            }
        }
        Err(_) => None,
    }
}

pub fn u8_vector(amount: u8) -> Vec<u8> {
    let mut v: Vec<u8> = vec![];

    for i in 0..amount {
        v.push(0);
    }

    v
}

pub fn read_r4c_file(arg: String) -> Option<Vec<u8>> {
    let mut output: Vec<u8> = vec![];
    let mut file = File::open(arg).unwrap();
    let mut buf = String::new();
    file.read_to_string(&mut buf);

    match buf.pop() { // nice
        Some(c) if c != '\n' => {
            println!("{}", c);
            buf.push(c);
        }
        _ => ()
    }

    let mut count = 0;
    let mut tmp = 0;

    for ch in buf.chars() {
        let s = ch.to_string();
        let u4 = match u8::from_str_radix(&s, 16) {
            Ok(e) => e,
            Err(e) => {
                panic!("I paniced with {:?} -- {:?}", s, e)
            }
        };
        if count % 2 == 0 {
            // output.push(u4);
            tmp = u4 << 4;
        } else {
            let back = tmp | u4;
            output.push(back);
        }
        count = count + 1;
    }

    Some(output)
}

pub fn read_file_from_arg(arg: Option<String>) -> Option<Vec<u8>> {
    match arg {
        Some(name) => {
            match File::open(name) {
                Ok(mut file) => {
                    let mut output: Vec<u8> = vec![];
                    match file.read_to_end(&mut output) {
                        Ok(_) => Some(output),
                        Err(_) => None,
                    }
                }
                Err(_) => None,
            }
        }
        None => None,
    }
}

// remember to add some stuff here...
// we could use the english dictionary supplied with every linux distro....
// maybe different for mac's and pc's
pub fn is_english(plain_text: String) -> bool {
    true
}

pub fn prompt(s: &str) {
    print!("{}", s);
    stdout().flush();
}
<|endoftext|>


<commit_before>// This is a part of rust-encoding.
// Copyright (c) 2013, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Internal utilities.

use std::str::CharRange;
use std::cast::transmute;

/// Unchecked conversion to `char`.
pub fn as_char<T:Integer+NumCast>(ch: T) -> char {
    unsafe { transmute(ch.to_u32().unwrap()) }
}

/// External iterator for a string's characters with its corresponding byte offset range.
pub struct StrCharIndexIterator<'r> {
    priv index: uint,
    priv string: &'r str,
}

impl<'r> Iterator<((uint,uint), char)> for StrCharIndexIterator<'r> {
    #[inline]
    fn next(&mut self) -> Option<((uint,uint), char)> {
        if self.index < self.string.len() {
            let CharRange {ch, next} = self.string.char_range_at(self.index);
            let prev = self.index;
            self.index = next;
            Some(((prev, next), ch))
        } else {
            None
        }
    }
}

/// A trait providing an `index_iter` method.
pub trait StrCharIndex<'r> {
    fn index_iter(&self) -> StrCharIndexIterator<'r>;
}

impl<'r> StrCharIndex<'r> for &'r str {
    /// Iterates over each character with corresponding byte offset range.
    fn index_iter(&self) -> StrCharIndexIterator<'r> {
        StrCharIndexIterator { index: 0, string: *self }
    }
}
<commit_msg>language changes: std::num::Integer no longer exists.<commit_after>// This is a part of rust-encoding.
// Copyright (c) 2013, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Internal utilities.

use std::str::CharRange;
use std::cast::transmute;

/// Unchecked conversion to `char`.
pub fn as_char<T:Int+NumCast>(ch: T) -> char {
    unsafe { transmute(ch.to_u32().unwrap()) }
}

/// External iterator for a string's characters with its corresponding byte offset range.
pub struct StrCharIndexIterator<'r> {
    priv index: uint,
    priv string: &'r str,
}

impl<'r> Iterator<((uint,uint), char)> for StrCharIndexIterator<'r> {
    #[inline]
    fn next(&mut self) -> Option<((uint,uint), char)> {
        if self.index < self.string.len() {
            let CharRange {ch, next} = self.string.char_range_at(self.index);
            let prev = self.index;
            self.index = next;
            Some(((prev, next), ch))
        } else {
            None
        }
    }
}

/// A trait providing an `index_iter` method.
pub trait StrCharIndex<'r> {
    fn index_iter(&self) -> StrCharIndexIterator<'r>;
}

impl<'r> StrCharIndex<'r> for &'r str {
    /// Iterates over each character with corresponding byte offset range.
    fn index_iter(&self) -> StrCharIndexIterator<'r> {
        StrCharIndexIterator { index: 0, string: *self }
    }
}
<|endoftext|>


<commit_before>use std::io::BufRead;

use quick_xml::events::attributes::Attributes;
use quick_xml::events::Event;
use quick_xml::Reader;

use crate::error::Error;
use std::str::FromStr;

/// Alias of `::chrono::DateTime<::chrono::FixedOffset>`
pub type FixedDateTime = ::chrono::DateTime<::chrono::FixedOffset>;

pub fn default_fixed_datetime() -> FixedDateTime {
    FixedDateTime::from_str("1970-01-01T00:00:00Z").unwrap()
}

fn non_empty(string: String) -> Option<String> {
    if !string.is_empty() {
        Some(string)
    } else {
        None
    }
}

pub fn atom_text(reader: &mut Reader) -> Result<Option<String>, Error> {
    let mut innerbuf = Vec::new();
    let mut depth = 0;
    let mut result = String::new();

    loop {
        match reader.read_event(&mut innerbuf)? {
            Event::Start(start) => {
                depth += 1;
                result.push('<');
                result.push_str(&start.unescape_and_decode(reader)?);
                result.push('>');
            }
            Event::End(end) => {
                if depth <= 0 {
                    break;
                }
                depth -= 1;
                result.push_str("</");
                result.push_str(&reader.decode(end.name()));
                result.push('>');
            }
            Event::Empty(start) => {
                depth += 1;
                result.push('<');
                result.push_str(&start.unescape_and_decode(reader)?);
                result.push_str("/>");
            }
            Event::CData(text) => {
                let decoded = text.unescape_and_decode(reader)?;
                result.push_str(&decoded);
            }
            Event::Text(text) => {
                let decoded = text.unescape_and_decode(reader)?;
                result.push_str(&decoded);
            }
            Event::Comment(text) => {
                let decoded = text.unescape_and_decode(reader)?;
                result.push_str("");
            }
            Event::Decl(_decl) => {}
            Event::PI(_text) => {}
            Event::DocType(_text) => {}
            Event::Eof => return Err(Error::Eof),
        }

        innerbuf.clear();
    }

    Ok(non_empty(result))
}

pub fn atom_xhtml(reader: &mut Reader) -> Result<Option<String>, Error> {
    let mut innerbuf = Vec::new();
    let mut depth = 0;
    let mut result = String::new();

    loop {
        match reader.read_event(&mut innerbuf)? {
            Event::Start(start) => {
                depth += 1;
                result.push('<');
                result.push_str(&start.unescape_and_decode(reader)?);
                result.push('>');
            }
            Event::End(end) => {
                if depth <= 0 {
                    break;
                }
                depth -= 1;
                result.push_str("</");
                result.push_str(&reader.decode(end.name()));
                result.push('>');
            }
            Event::Empty(start) => {
                depth += 1;
                result.push('<');
                result.push_str(&start.unescape_and_decode(reader)?);
                result.push_str("/>");
            }
            Event::CData(text) => {
                let decoded = reader.decode(text.escaped());
                result.push_str(&decoded);
            }
            Event::Text(text) => {
                let decoded = reader.decode(text.escaped());
                result.push_str(&decoded);
            }
            Event::Comment(text) => {
                let decoded = text.unescape_and_decode(reader)?;
                result.push_str("");
            }
            Event::Decl(_decl) => {}
            Event::PI(_text) => {}
            Event::DocType(_text) => {}
            Event::Eof => return Err(Error::Eof),
        }

        innerbuf.clear();
    }

    Ok(non_empty(result))
}

pub fn atom_any_text(
    reader: &mut Reader,
    mut atts: Attributes<'_>,
) -> Result<Option<String>, Error> {
    let content_type = atts
        .with_checks(false)
        .flatten()
        .find(|attr| attr.key == b"type")
        .map(|attr| attr.unescape_and_decode_value(reader))
        .transpose()?;

    match content_type {
        Some(ref t) if t == "xhtml" => atom_xhtml(reader),
        _ => atom_text(reader),
    }
}

pub fn atom_datetime(reader: &mut Reader) -> Result<Option<FixedDateTime>, Error> {
    if let Some(datetime_text) = atom_text(reader)? {
        match diligent_date_parser::parse_date(&datetime_text) {
            None => Err(Error::WrongDatetime(datetime_text)),
            Some(datetime) => Ok(Some(datetime)),
        }
    } else {
        Ok(None)
    }
}
<commit_msg>Fix reading of open tags in text/content elements<commit_after>use std::io::BufRead;

use quick_xml::events::attributes::Attributes;
use quick_xml::events::Event;
use quick_xml::Reader;

use crate::error::Error;
use std::str::FromStr;

/// Alias of `::chrono::DateTime<::chrono::FixedOffset>`
pub type FixedDateTime = ::chrono::DateTime<::chrono::FixedOffset>;

pub fn default_fixed_datetime() -> FixedDateTime {
    FixedDateTime::from_str("1970-01-01T00:00:00Z").unwrap()
}

fn non_empty(string: String) -> Option<String> {
    if !string.is_empty() {
        Some(string)
    } else {
        None
    }
}

pub fn atom_text(reader: &mut Reader) -> Result<Option<String>, Error> {
    reader.expand_empty_elements(false);

    let mut innerbuf = Vec::new();
    let mut depth = 0;
    let mut result = String::new();

    loop {
        match reader.read_event(&mut innerbuf)? {
            Event::Start(start) => {
                depth += 1;
                result.push('<');
                result.push_str(&start.unescape_and_decode(reader)?);
                result.push('>');
            }
            Event::End(end) => {
                if depth <= 0 {
                    break;
                }
                depth -= 1;
                result.push_str("</");
                result.push_str(&reader.decode(end.name()));
                result.push('>');
            }
            Event::Empty(start) => {
                result.push('<');
                result.push_str(&start.unescape_and_decode(reader)?);
                result.push_str("/>");
            }
            Event::CData(text) => {
                let decoded = text.unescape_and_decode(reader)?;
                result.push_str(&decoded);
            }
            Event::Text(text) => {
                let decoded = text.unescape_and_decode(reader)?;
                result.push_str(&decoded);
            }
            Event::Comment(text) => {
                let decoded = text.unescape_and_decode(reader)?;
                result.push_str("");
            }
            Event::Decl(_decl) => {}
            Event::PI(_text) => {}
            Event::DocType(_text) => {}
            Event::Eof => return Err(Error::Eof),
        }

        innerbuf.clear();
    }

    reader.expand_empty_elements(true);

    Ok(non_empty(result))
}

pub fn atom_xhtml(reader: &mut Reader) -> Result<Option<String>, Error> {
    reader.expand_empty_elements(false);

    let mut innerbuf = Vec::new();
    let mut depth = 0;
    let mut result = String::new();

    loop {
        match reader.read_event(&mut innerbuf)? {
            Event::Start(start) => {
                depth += 1;
                result.push('<');
                result.push_str(&start.unescape_and_decode(reader)?);
                result.push('>');
            }
            Event::End(end) => {
                if depth <= 0 {
                    break;
                }
                depth -= 1;
                result.push_str("</");
                result.push_str(&reader.decode(end.name()));
                result.push('>');
            }
            Event::Empty(start) => {
                result.push('<');
                result.push_str(&start.unescape_and_decode(reader)?);
                result.push_str("/>");
            }
            Event::CData(text) => {
                let decoded = reader.decode(text.escaped());
                result.push_str(&decoded);
            }
            Event::Text(text) => {
                let decoded = reader.decode(text.escaped());
                result.push_str(&decoded);
            }
            Event::Comment(text) => {
                let decoded = text.unescape_and_decode(reader)?;
                result.push_str("");
            }
            Event::Decl(_decl) => {}
            Event::PI(_text) => {}
            Event::DocType(_text) => {}
            Event::Eof => return Err(Error::Eof),
        }

        innerbuf.clear();
    }

    reader.expand_empty_elements(true);

    Ok(non_empty(result))
}

pub fn atom_any_text(
    reader: &mut Reader,
    mut atts: Attributes<'_>,
) -> Result<Option<String>, Error> {
    let content_type = atts
        .with_checks(false)
        .flatten()
        .find(|attr| attr.key == b"type")
        .map(|attr| attr.unescape_and_decode_value(reader))
        .transpose()?;

    match content_type {
        Some(ref t) if t == "xhtml" => atom_xhtml(reader),
        _ => atom_text(reader),
    }
}

pub fn atom_datetime(reader: &mut Reader) -> Result<Option<FixedDateTime>, Error> {
    if let Some(datetime_text) = atom_text(reader)? {
        match diligent_date_parser::parse_date(&datetime_text) {
            None => Err(Error::WrongDatetime(datetime_text)),
            Some(datetime) => Ok(Some(datetime)),
        }
    } else {
        Ok(None)
    }
}

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

    fn read_x(xml: &str) -> Result<Option<String>, Error> {
        let mut reader = Reader::from_reader(xml.as_bytes());
        reader.expand_empty_elements(true);
        loop {
            let mut buf = Vec::new();
            match reader.read_event(&mut buf)? {
                Event::Start(element) if element.name() == b"text" => {
                    return atom_text(&mut reader)
                }
                Event::Start(element) if element.name() == b"raw" => {
                    return atom_xhtml(&mut reader)
                }
                Event::Start(_) => return Err(Error::InvalidStartTag),
                Event::Eof => return Err(Error::Eof),
                _ => {}
            }
        }
    }

    #[test]
    fn test_read_text() {
        let xml_fragment = r#"<text>
            Text with ampersand & <tag> and <unescaped-empty-tag />.
        </text>"#;
        assert_eq!(
            read_x(xml_fragment).unwrap().unwrap().trim(),
            "Text with ampersand & <tag> and <unescaped-empty-tag />."
        );
    }

    #[test]
    fn test_read_xhtml() {
        let xml_fragment = r#"<raw>

a line
& one more

        </raw>"#;
        assert_eq!(
            read_x(xml_fragment).unwrap().unwrap().trim(),
            r#"
a line
& one more
"#
        );
    }
}
<|endoftext|>


<commit_before>use grid;
use pancurses;
use pancurses::{Window, Attribute, Attributes, ColorPair, ToChtype};
use sprite;
use sprite::{Sprite, Color};
use geometry::*;
use util::pick;
use world::World;
use log::Log;
use item::Inventory;

fn color(color: Color) -> Attributes {
    match color {
        Color::Navy   => (Attributes::new() | ColorPair(1)),
        Color::Green  => (Attributes::new() | ColorPair(2)),
        Color::Teal   => (Attributes::new() | ColorPair(3)),
        Color::Maroon => (Attributes::new() | ColorPair(4)),
        Color::Purple => (Attributes::new() | ColorPair(5)),
        Color::Brown  => (Attributes::new() | ColorPair(6)),
        Color::Gray   => (Attributes::new() | ColorPair(0)),
        Color::Dark   => (Attribute::Bold   | ColorPair(7)),
        Color::Blue   => (Attribute::Bold   | ColorPair(1)),
        Color::Lime   => (Attribute::Bold   | ColorPair(2)),
        Color::Aqua   => (Attribute::Bold   | ColorPair(3)),
        Color::Red    => (Attribute::Bold   | ColorPair(4)),
        Color::Pink   => (Attribute::Bold   | ColorPair(5)),
        Color::Yellow => (Attribute::Bold   | ColorPair(6)),
        Color::White  => (Attribute::Bold   | ColorPair(0)),
    }
}

fn cell(sprite: Sprite) -> pancurses::chtype {
    sprite.character.to_chtype() | pancurses::chtype::from(color(*pick(sprite.color)))
}

pub fn initialize() -> Window {
    let terminal = pancurses::initscr();
    pancurses::cbreak();
    pancurses::noecho();
    pancurses::curs_set(0);

    pancurses::start_color();
    pancurses::init_pair(0, pancurses::COLOR_WHITE,   pancurses::COLOR_BLACK);
    pancurses::init_pair(1, pancurses::COLOR_BLUE,    pancurses::COLOR_BLACK);
    pancurses::init_pair(2, pancurses::COLOR_GREEN,   pancurses::COLOR_BLACK);
    pancurses::init_pair(3, pancurses::COLOR_CYAN,    pancurses::COLOR_BLACK);
    pancurses::init_pair(4, pancurses::COLOR_RED,     pancurses::COLOR_BLACK);
    pancurses::init_pair(5, pancurses::COLOR_MAGENTA, pancurses::COLOR_BLACK);
    pancurses::init_pair(6, pancurses::COLOR_YELLOW,  pancurses::COLOR_BLACK);
    pancurses::init_pair(7, pancurses::COLOR_BLACK,   pancurses::COLOR_BLACK);

    // NOTE: only used for drawing border; remove if we end up not needing this
    pancurses::init_pair(8, pancurses::COLOR_BLUE, pancurses::COLOR_BLUE);

    terminal
}

// TODO: write an actual dang view

pub fn draw(term: &Window, world: &World) {
    term.erase(); // clear back-buffer

    // draw border (NOTE: remove color pair 8 if we remove this)
    // TODO: depend on terminal size; don't hardcode lengths/alignments
    let blue = '#'.to_chtype() | pancurses::chtype::from(ColorPair(8));
    for position in grid::RECTANGLE.grow(1) {
        let Point(col, row) = position;
        term.mvaddch(row + 4, col + 30, blue);
    }

    draw_inventory(term, &world.player.inventory);

    draw_board(term, &world);

    draw_messages(term, &world.log);

    term.refresh();
}

fn draw_board(term: &Window, world: &World) {
    // TODO: depend on terminal size; don't hardcode lengths/alignments
    term.attrset(Attributes::new());
    let level = world.player.current_level(&world.dungeon);
    for row in 0..grid::HEIGHT as i32 {
        term.mv(row + 4, 30);
        for col in 0..grid::WIDTH as i32 {
            let position = Point(col, row);
            let sprite =
                if level.known_tiles.contains(&position) {
                    let visible = world.player.visible.contains(&position);
                    level.sprite_at(position, &world).darken(!visible)
                } else {
                    sprite::HIDDEN
                };
            term.addch(cell(sprite));
        }
    }
}

fn draw_messages(term: &Window, log: &Log) {
    // TODO: depend on terminal size; don't hardcode lengths/alignments;
    //       visually group messages by turn (underscore separators? color?);
    //       maybe group similar messages; add linewrapping if needed
    term.attrset(Attributes::new());
    for (i, &(_, ref message)) in log.recent_messages().iter().take(6).enumerate() {
        term.mvaddstr(23 - i as i32, 0, &message);
    }
}

fn draw_inventory(term: &Window, inventory: &Inventory) {
    // TODO: depend on terminal size; don't hardcode lengths/alignments
    // TODO: abbreviate long inventory slot descriptions
    for (index, slot) in inventory.slots.iter().enumerate() {
        let index_color = if !slot.is_empty() {
            Color::Blue
        } else {
            Color::Dark
        };
        term.attrset(color(index_color));
        term.mvaddstr(index as i32 + 4, 0, &(index+1).to_string());

        let text_color = if slot.is_cursed() {
            if slot.is_equipped() {Color::Red} else {Color::Maroon}
        } else if !slot.is_empty() {
            if slot.is_equipped() {Color::White} else {Color::Gray}
        } else {
            Color::Dark
        };
        term.attrset(color(text_color));

        if slot.is_cursed() {
            term.addstr(" cursed");
        }

        if slot.is_enchanted() {
            term.addstr(" enchanted");
        }

        term.addch(' ');
        let name = match slot.get_item() {
            Some(item) => item.name(),
            None => "nothing"
        };
        term.addstr(name);

        if slot.is_equipped() {
            term.addstr("(equipped)");
        }
    }
}
<commit_msg>base level border on wall color<commit_after>use grid;
use pancurses;
use pancurses::{Window, Attribute, Attributes, ColorPair, ToChtype};
use sprite;
use sprite::{Sprite, Color};
use geometry::*;
use util::pick;
use world::World;
use log::Log;
use item::Inventory;
use tile::Tile;

fn color(color: Color) -> Attributes {
    match color {
        Color::Navy   => (Attributes::new() | ColorPair(1)),
        Color::Green  => (Attributes::new() | ColorPair(2)),
        Color::Teal   => (Attributes::new() | ColorPair(3)),
        Color::Maroon => (Attributes::new() | ColorPair(4)),
        Color::Purple => (Attributes::new() | ColorPair(5)),
        Color::Brown  => (Attributes::new() | ColorPair(6)),
        Color::Gray   => (Attributes::new() | ColorPair(0)),
        Color::Dark   => (Attribute::Bold   | ColorPair(7)),
        Color::Blue   => (Attribute::Bold   | ColorPair(1)),
        Color::Lime   => (Attribute::Bold   | ColorPair(2)),
        Color::Aqua   => (Attribute::Bold   | ColorPair(3)),
        Color::Red    => (Attribute::Bold   | ColorPair(4)),
        Color::Pink   => (Attribute::Bold   | ColorPair(5)),
        Color::Yellow => (Attribute::Bold   | ColorPair(6)),
        Color::White  => (Attribute::Bold   | ColorPair(0)),
    }
}

fn cell(sprite: Sprite) -> pancurses::chtype {
    sprite.character.to_chtype() | pancurses::chtype::from(color(*pick(sprite.color)))
}

pub fn initialize() -> Window {
    let terminal = pancurses::initscr();
    pancurses::cbreak();
    pancurses::noecho();
    pancurses::curs_set(0);

    pancurses::start_color();
    pancurses::init_pair(0, pancurses::COLOR_WHITE,   pancurses::COLOR_BLACK);
    pancurses::init_pair(1, pancurses::COLOR_BLUE,    pancurses::COLOR_BLACK);
    pancurses::init_pair(2, pancurses::COLOR_GREEN,   pancurses::COLOR_BLACK);
    pancurses::init_pair(3, pancurses::COLOR_CYAN,    pancurses::COLOR_BLACK);
    pancurses::init_pair(4, pancurses::COLOR_RED,     pancurses::COLOR_BLACK);
    pancurses::init_pair(5, pancurses::COLOR_MAGENTA, pancurses::COLOR_BLACK);
    pancurses::init_pair(6, pancurses::COLOR_YELLOW,  pancurses::COLOR_BLACK);
    pancurses::init_pair(7, pancurses::COLOR_BLACK,   pancurses::COLOR_BLACK);

    terminal
}

// TODO: write an actual dang view

pub fn draw(term: &Window, world: &World) {
    term.erase(); // clear back-buffer

    draw_inventory(term, &world.player.inventory);

    draw_board(term, &world);

    draw_messages(term, &world.log);

    term.refresh();
}

fn draw_board(term: &Window, world: &World) {
    // TODO: depend on terminal size; don't hardcode lengths/alignments
    term.attrset(Attributes::new());

    draw_border(term, world);

    let level = world.player.current_level(&world.dungeon);
    for row in 0..grid::HEIGHT as i32 {
        term.mv(row + 4, 30);
        for col in 0..grid::WIDTH as i32 {
            let position = Point(col, row);
            let sprite =
                if level.known_tiles.contains(&position) {
                    let visible = world.player.visible.contains(&position);
                    level.sprite_at(position, &world).darken(!visible)
                } else {
                    sprite::HIDDEN
                };
            term.addch(cell(sprite));
        }
    }
}

fn draw_border(term: &Window, world: &World) {
    // TODO: depend on terminal size; don't hardcode lengths/alignments

    let border = cell(Sprite {
        character: ' ',
        color: Tile::Wall.sprite(world).color
    }) | pancurses::chtype::from(Attribute::Reverse);

    for position in grid::RECTANGLE.grow(1) {
        let Point(col, row) = position;
        term.mvaddch(row + 4, col + 30, border);
    }
}

fn draw_messages(term: &Window, log: &Log) {
    // TODO: depend on terminal size; don't hardcode lengths/alignments;
    //       visually group messages by turn (underscore separators? color?);
    //       maybe group similar messages; add linewrapping if needed
    term.attrset(Attributes::new());
    for (i, &(_, ref message)) in log.recent_messages().iter().take(6).enumerate() {
        term.mvaddstr(23 - i as i32, 0, &message);
    }
}

fn draw_inventory(term: &Window, inventory: &Inventory) {
    // TODO: depend on terminal size; don't hardcode lengths/alignments
    // TODO: abbreviate long inventory slot descriptions
    for (index, slot) in inventory.slots.iter().enumerate() {
        let index_color = if !slot.is_empty() {
            Color::Blue
        } else {
            Color::Dark
        };
        term.attrset(color(index_color));
        term.mvaddstr(index as i32 + 4, 0, &(index+1).to_string());

        let text_color = if slot.is_cursed() {
            if slot.is_equipped() {Color::Red} else {Color::Maroon}
        } else if !slot.is_empty() {
            if slot.is_equipped() {Color::White} else {Color::Gray}
        } else {
            Color::Dark
        };
        term.attrset(color(text_color));

        if slot.is_cursed() {
            term.addstr(" cursed");
        }

        if slot.is_enchanted() {
            term.addstr(" enchanted");
        }

        term.addch(' ');
        let name = match slot.get_item() {
            Some(item) => item.name(),
            None => "nothing"
        };
        term.addstr(name);

        if slot.is_equipped() {
            term.addstr("(equipped)");
        }
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;

use client::Client;
use std::collections::HashMap;

#[derive(Debug)]
pub struct Plan {
}

impl Plan {

    pub fn new<S: Into<String>>(
        name: S,
        amount: i32,
        currency_code: S,
        interval: S,
        interval_count: i32,
        trial_days: i32,
        limit: Option<i32>,
        metadata: Option<HashMap<String, serde_json::Value>>
    ) -> HashMap<String, serde_json::Value> {
        let mut map: HashMap<String, serde_json::Value>;
        map = HashMap::new();
        map.insert("name".to_string(), json!(name.into()));
        map.insert("amount".to_string(), json!(amount));
        map.insert("currency_code".to_string(), json!(currency_code.into()));
        map.insert("interval".to_string(), json!(interval.into()));
        map.insert("interval_count".to_string(), json!(interval_count));
        map.insert("trial_days".to_string(), json!(trial_days));
        if !limit.is_none() {
            map.insert("limit".to_string(), json!(limit));
        }
        if !metadata.is_none() {
            map.insert("metadata".to_string(), json!(metadata));
        }
        return map;
    }

    pub fn create(client: &Client, plan: &HashMap<String, serde_json::Value>) -> String {
        client.post("/plans", plan)
    }

    pub fn delete(client: &Client, id: &str) -> String {
        client.delete(&format!("/plans/{}", id))
    }

    pub fn retrieve(client: &Client, id: &str) -> String {
        client.get(&format!("/plans/{}", id))
    }

    pub fn all(
        client: &Client,
        query_params: Option<HashMap<String, String>>,
        limit: Option<String>,
        before: Option<String>,
        after: Option<String>
    ) -> String {
        client.get_filter("/plans", query_params, limit, before, after)
    }

}
<commit_msg>add documentation for Plan<commit_after>extern crate serde_json;

use client::Client;
use std::collections::HashMap;

#[derive(Debug)]
pub struct Plan {
}

impl Plan {

    //! # Examples
    //!
    //! ```
    //! let client = culqi::Client::new("{KEY}");
    //! ```
    //!
    //! ```
    //! let new_plan = culqi::Plan::new("Hooli Subscription",1000,"PEN","meses",3,15,2,None);
    //! ```
    //!
    //! ```
    //! let create_plan = culqi::Plan::create(&client, &new_plan);
    //! ```
    //!
    //! ```
    //! let get_plan = culqi::Plan::retrieve(&client, "{ID}");
    //! ```
    //!
    //! ```
    //! let delete_plan = culqi::Plan::delete(&client, "{ID}");
    //! ```
    //!
    //!
    //! Here you are the list of filters you can use for get Refunds
    //!
    //! ```
    //! use std::collections::HashMap;
    //! ```
    //!
    //! ```
    //! let mut plan_filter: HashMap<String, String>;
    //! plan_filter = HashMap::new();
    //! plan_filter.insert("amount".to_string(), "100".to_string());
    //! plan_filter.insert("min_amount".to_string(), "100".to_string());
    //! plan_filter.insert("max_amount".to_string(), "2000".to_string());
    //! plan_filter.insert("interval".to_string(), "meses".to_string());
    //! ```
    //!
    //! It must uses [Unix Timestamp](http://www.unixtimestamp.com/index.php)
    //!
    //! ```
    //! plan_filter.insert("creation_date".to_string(), "1484006400".to_string());
    //! plan_filter.insert("creation_date_from".to_string(), "1479600000".to_string());
    //! plan_filter.insert("creation_date_to".to_string(), "1484006400".to_string());
    //! ```
    //!
    //! ```
    //! let all_plans = culqi::Plan::all(&client, Some(plan_filter), None, None, None);
    //! ```
    //!

    pub fn new<S: Into<String>>(
        name: S,
        amount: i32,
        currency_code: S,
        interval: S,
        interval_count: i32,
        trial_days: i32,
        limit: Option<i32>,
        metadata: Option<HashMap<String, serde_json::Value>>
    ) -> HashMap<String, serde_json::Value> {
        let mut map: HashMap<String, serde_json::Value>;
        map = HashMap::new();
        map.insert("name".to_string(), json!(name.into()));
        map.insert("amount".to_string(), json!(amount));
        map.insert("currency_code".to_string(), json!(currency_code.into()));
        map.insert("interval".to_string(), json!(interval.into()));
        map.insert("interval_count".to_string(), json!(interval_count));
        map.insert("trial_days".to_string(), json!(trial_days));
        if !limit.is_none() {
            map.insert("limit".to_string(), json!(limit));
        }
        if !metadata.is_none() {
            map.insert("metadata".to_string(), json!(metadata));
        }
        return map;
    }

    pub fn create(client: &Client, plan: &HashMap<String, serde_json::Value>) -> String {
        client.post("/plans", plan)
    }

    pub fn delete(client: &Client, id: &str) -> String {
        client.delete(&format!("/plans/{}", id))
    }

    pub fn retrieve(client: &Client, id: &str) -> String {
        client.get(&format!("/plans/{}", id))
    }

    pub fn all(
        client: &Client,
        query_params: Option<HashMap<String, String>>,
        limit: Option<String>,
        before: Option<String>,
        after: Option<String>
    ) -> String {
        client.get_filter("/plans", query_params, limit, before, after)
    }

}
<|endoftext|>


<commit_before>use crate::mir::interpret::InterpResult;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_target::abi::{Size, TargetDataLayout};
use std::convert::{TryFrom, TryInto};
use std::fmt;

#[derive(Copy, Clone)]
/// A type for representing any integer. Only used for printing.
pub struct ConstInt {
    /// The "untyped" variant of `ConstInt`.
    int: ScalarInt,
    /// Whether the value is of a signed integer type.
    signed: bool,
    /// Whether the value is a `usize` or `isize` type.
    is_ptr_sized_integral: bool,
}

impl ConstInt {
    pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
        Self { int, signed, is_ptr_sized_integral }
    }
}

impl std::fmt::Debug for ConstInt {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let Self { int, signed, is_ptr_sized_integral } = *self;
        let size = int.size().bytes();
        let raw = int.data;
        if signed {
            let bit_size = size * 8;
            let min = 1u128 << (bit_size - 1);
            let max = min - 1;
            if raw == min {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MIN"),
                    (1, _) => write!(fmt, "i8::MIN"),
                    (2, _) => write!(fmt, "i16::MIN"),
                    (4, _) => write!(fmt, "i32::MIN"),
                    (8, _) => write!(fmt, "i64::MIN"),
                    (16, _) => write!(fmt, "i128::MIN"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MAX"),
                    (1, _) => write!(fmt, "i8::MAX"),
                    (2, _) => write!(fmt, "i16::MAX"),
                    (4, _) => write!(fmt, "i32::MAX"),
                    (8, _) => write!(fmt, "i64::MAX"),
                    (16, _) => write!(fmt, "i128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as i8)?,
                    2 => write!(fmt, "{}", raw as i16)?,
                    4 => write!(fmt, "{}", raw as i32)?,
                    8 => write!(fmt, "{}", raw as i64)?,
                    16 => write!(fmt, "{}", raw as i128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_isize")?,
                        (1, _) => write!(fmt, "_i8")?,
                        (2, _) => write!(fmt, "_i16")?,
                        (4, _) => write!(fmt, "_i32")?,
                        (8, _) => write!(fmt, "_i64")?,
                        (16, _) => write!(fmt, "_i128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        } else {
            let max = Size::from_bytes(size).truncate(u128::MAX);
            if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "usize::MAX"),
                    (1, _) => write!(fmt, "u8::MAX"),
                    (2, _) => write!(fmt, "u16::MAX"),
                    (4, _) => write!(fmt, "u32::MAX"),
                    (8, _) => write!(fmt, "u64::MAX"),
                    (16, _) => write!(fmt, "u128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as u8)?,
                    2 => write!(fmt, "{}", raw as u16)?,
                    4 => write!(fmt, "{}", raw as u32)?,
                    8 => write!(fmt, "{}", raw as u64)?,
                    16 => write!(fmt, "{}", raw as u128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_usize")?,
                        (1, _) => write!(fmt, "_u8")?,
                        (2, _) => write!(fmt, "_u16")?,
                        (4, _) => write!(fmt, "_u32")?,
                        (8, _) => write!(fmt, "_u64")?,
                        (16, _) => write!(fmt, "_u128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        }
    }
}

/// The raw bytes of a simple value.
///
/// This is a packed struct in order to allow this type to be optimally embedded in enums
/// (like Scalar).
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(packed)]
pub struct ScalarInt {
    /// The first `size` bytes of `data` are the value.
    /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
    data: u128,
    size: u8,
}

// Cannot derive these, as the derives take references to the fields, and we
// can't take references to fields of packed structs.
impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) {
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`.
        // Since `Self` is a packed struct, that would create a possibly unaligned reference,
        // which is UB.
        { self.data }.hash_stable(hcx, hasher);
        self.size.hash_stable(hcx, hasher);
    }
}

impl<S: Encoder> Encodable<S> for ScalarInt {
    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_u128(self.data)?;
        s.emit_u8(self.size)
    }
}

impl<D: Decoder> Decodable<D> for ScalarInt {
    fn decode(d: &mut D) -> Result<ScalarInt, D::Error> {
        Ok(ScalarInt { data: d.read_u128()?, size: d.read_u8()? })
    }
}

impl ScalarInt {
    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 };

    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: 1 };

    pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 };

    #[inline]
    pub fn size(self) -> Size {
        Size::from_bytes(self.size)
    }

    /// Make sure the `data` fits in `size`.
    /// This is guaranteed by all constructors here, but having had this check saved us from
    /// bugs many times in the past, so keeping it around is definitely worth it.
    #[inline(always)]
    fn check_data(self) {
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `assert_eq` takes references to its arguments and formatting
        // arguments and would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB.
        debug_assert_eq!(
            self.size().truncate(self.data),
            { self.data },
            "Scalar value {:#x} exceeds size of {} bytes",
            { self.data },
            self.size
        );
    }

    #[inline]
    pub fn null(size: Size) -> Self {
        Self { data: 0, size: size.bytes() as u8 }
    }

    #[inline]
    pub fn is_null(self) -> bool {
        self.data == 0
    }

    pub(crate) fn ptr_sized_op<'tcx>(
        self,
        dl: &TargetDataLayout,
        f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>,
    ) -> InterpResult<'tcx, Self> {
        assert_eq!(u64::from(self.size), dl.pointer_size.bytes());
        Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size()).unwrap())
    }

    #[inline]
    pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
        let data = i.into();
        if size.truncate(data) == data {
            Some(Self { data, size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
        let i = i.into();
        // `into` performed sign extension, we have to truncate
        let truncated = size.truncate(i as u128);
        if size.sign_extend(truncated) as i128 == i {
            Some(Self { data: truncated, size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn assert_bits(self, target_size: Size) -> u128 {
        self.to_bits(target_size).unwrap_or_else(|size| {
            bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes())
        })
    }

    #[inline]
    pub fn to_bits(self, target_size: Size) -> Result<u128, Size> {
        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
        if target_size.bytes() == u64::from(self.size) {
            self.check_data();
            Ok(self.data)
        } else {
            Err(self.size())
        }
    }
}

macro_rules! from {
    ($($ty:ty),*) => {
        $(
            impl From<$ty> for ScalarInt {
                #[inline]
                fn from(u: $ty) -> Self {
                    Self {
                        data: u128::from(u),
                        size: std::mem::size_of::<$ty>() as u8,
                    }
                }
            }
        )*
    }
}

macro_rules! try_from {
    ($($ty:ty),*) => {
        $(
            impl TryFrom<ScalarInt> for $ty {
                type Error = Size;
                #[inline]
                fn try_from(int: ScalarInt) -> Result<Self, Size> {
                    // The `unwrap` cannot fail because to_bits (if it succeeds)
                    // is guaranteed to return a value that fits into the size.
                    int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>()))
                       .map(|u| u.try_into().unwrap())
                }
            }
        )*
    }
}

from!(u8, u16, u32, u64, u128, bool);
try_from!(u8, u16, u32, u64, u128);

impl From<char> for ScalarInt {
    #[inline]
    fn from(c: char) -> Self {
        Self { data: c as u128, size: std::mem::size_of::<char>() as u8 }
    }
}

impl TryFrom<ScalarInt> for char {
    type Error = Size;
    #[inline]
    fn try_from(int: ScalarInt) -> Result<Self, Size> {
        int.to_bits(Size::from_bytes(std::mem::size_of::<char>()))
            .map(|u| char::from_u32(u.try_into().unwrap()).unwrap())
    }
}

impl From<Single> for ScalarInt {
    #[inline]
    fn from(f: Single) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { data: f.to_bits(), size: 4 }
    }
}

impl TryFrom<ScalarInt> for Single {
    type Error = Size;
    #[inline]
    fn try_from(int: ScalarInt) -> Result<Self, Size> {
        int.to_bits(Size::from_bytes(4)).map(Self::from_bits)
    }
}

impl From<Double> for ScalarInt {
    #[inline]
    fn from(f: Double) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { data: f.to_bits(), size: 8 }
    }
}

impl TryFrom<ScalarInt> for Double {
    type Error = Size;
    #[inline]
    fn try_from(int: ScalarInt) -> Result<Self, Size> {
        int.to_bits(Size::from_bytes(8)).map(Self::from_bits)
    }
}

impl fmt::Debug for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.size == 0 {
            self.check_data();
            write!(f, "<ZST>")
        } else {
            // Dispatch to LowerHex below.
            write!(f, "0x{:x}", self)
        }
    }
}

impl fmt::LowerHex for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.check_data();
        // Format as hex number wide enough to fit any value of the given `size`.
        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `write!` takes references to its formatting arguments and
        // would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB.
        write!(f, "{:01$x}", { self.data }, self.size as usize * 2)
    }
}

impl fmt::UpperHex for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.check_data();
        // Format as hex number wide enough to fit any value of the given `size`.
        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `write!` takes references to its formatting arguments and
        // would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB.
        write!(f, "{:01$X}", { self.data }, self.size as usize * 2)
    }
}
<commit_msg>Make `ScalarInt` entirely independent of MIR interpretation<commit_after>use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_target::abi::{Size, TargetDataLayout};
use std::convert::{TryFrom, TryInto};
use std::fmt;

#[derive(Copy, Clone)]
/// A type for representing any integer. Only used for printing.
pub struct ConstInt {
    /// The "untyped" variant of `ConstInt`.
    int: ScalarInt,
    /// Whether the value is of a signed integer type.
    signed: bool,
    /// Whether the value is a `usize` or `isize` type.
    is_ptr_sized_integral: bool,
}

impl ConstInt {
    pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
        Self { int, signed, is_ptr_sized_integral }
    }
}

impl std::fmt::Debug for ConstInt {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let Self { int, signed, is_ptr_sized_integral } = *self;
        let size = int.size().bytes();
        let raw = int.data;
        if signed {
            let bit_size = size * 8;
            let min = 1u128 << (bit_size - 1);
            let max = min - 1;
            if raw == min {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MIN"),
                    (1, _) => write!(fmt, "i8::MIN"),
                    (2, _) => write!(fmt, "i16::MIN"),
                    (4, _) => write!(fmt, "i32::MIN"),
                    (8, _) => write!(fmt, "i64::MIN"),
                    (16, _) => write!(fmt, "i128::MIN"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MAX"),
                    (1, _) => write!(fmt, "i8::MAX"),
                    (2, _) => write!(fmt, "i16::MAX"),
                    (4, _) => write!(fmt, "i32::MAX"),
                    (8, _) => write!(fmt, "i64::MAX"),
                    (16, _) => write!(fmt, "i128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as i8)?,
                    2 => write!(fmt, "{}", raw as i16)?,
                    4 => write!(fmt, "{}", raw as i32)?,
                    8 => write!(fmt, "{}", raw as i64)?,
                    16 => write!(fmt, "{}", raw as i128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_isize")?,
                        (1, _) => write!(fmt, "_i8")?,
                        (2, _) => write!(fmt, "_i16")?,
                        (4, _) => write!(fmt, "_i32")?,
                        (8, _) => write!(fmt, "_i64")?,
                        (16, _) => write!(fmt, "_i128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        } else {
            let max = Size::from_bytes(size).truncate(u128::MAX);
            if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "usize::MAX"),
                    (1, _) => write!(fmt, "u8::MAX"),
                    (2, _) => write!(fmt, "u16::MAX"),
                    (4, _) => write!(fmt, "u32::MAX"),
                    (8, _) => write!(fmt, "u64::MAX"),
                    (16, _) => write!(fmt, "u128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as u8)?,
                    2 => write!(fmt, "{}", raw as u16)?,
                    4 => write!(fmt, "{}", raw as u32)?,
                    8 => write!(fmt, "{}", raw as u64)?,
                    16 => write!(fmt, "{}", raw as u128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_usize")?,
                        (1, _) => write!(fmt, "_u8")?,
                        (2, _) => write!(fmt, "_u16")?,
                        (4, _) => write!(fmt, "_u32")?,
                        (8, _) => write!(fmt, "_u64")?,
                        (16, _) => write!(fmt, "_u128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        }
    }
}

/// The raw bytes of a simple value.
///
/// This is a packed struct in order to allow this type to be optimally embedded in enums
/// (like Scalar).
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(packed)]
pub struct ScalarInt {
    /// The first `size` bytes of `data` are the value.
    /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
    data: u128,
    size: u8,
}

// Cannot derive these, as the derives take references to the fields, and we
// can't take references to fields of packed structs.
impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) {
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`.
        // Since `Self` is a packed struct, that would create a possibly unaligned reference,
        // which is UB.
        { self.data }.hash_stable(hcx, hasher);
        self.size.hash_stable(hcx, hasher);
    }
}

impl<S: Encoder> Encodable<S> for ScalarInt {
    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_u128(self.data)?;
        s.emit_u8(self.size)
    }
}

impl<D: Decoder> Decodable<D> for ScalarInt {
    fn decode(d: &mut D) -> Result<ScalarInt, D::Error> {
        Ok(ScalarInt { data: d.read_u128()?, size: d.read_u8()? })
    }
}

impl ScalarInt {
    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 };

    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: 1 };

    pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 };

    #[inline]
    pub fn size(self) -> Size {
        Size::from_bytes(self.size)
    }

    /// Make sure the `data` fits in `size`.
    /// This is guaranteed by all constructors here, but having had this check saved us from
    /// bugs many times in the past, so keeping it around is definitely worth it.
    #[inline(always)]
    fn check_data(self) {
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `assert_eq` takes references to its arguments and formatting
        // arguments and would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB.
        debug_assert_eq!(
            self.size().truncate(self.data),
            { self.data },
            "Scalar value {:#x} exceeds size of {} bytes",
            { self.data },
            self.size
        );
    }

    #[inline]
    pub fn null(size: Size) -> Self {
        Self { data: 0, size: size.bytes() as u8 }
    }

    #[inline]
    pub fn is_null(self) -> bool {
        self.data == 0
    }

    pub(crate) fn ptr_sized_op<E>(
        self,
        dl: &TargetDataLayout,
        f_int: impl FnOnce(u64) -> Result<u64, E>,
    ) -> Result<Self, E> {
        assert_eq!(u64::from(self.size), dl.pointer_size.bytes());
        Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size()).unwrap())
    }

    #[inline]
    pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
        let data = i.into();
        if size.truncate(data) == data {
            Some(Self { data, size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
        let i = i.into();
        // `into` performed sign extension, we have to truncate
        let truncated = size.truncate(i as u128);
        if size.sign_extend(truncated) as i128 == i {
            Some(Self { data: truncated, size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn assert_bits(self, target_size: Size) -> u128 {
        self.to_bits(target_size).unwrap_or_else(|size| {
            bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes())
        })
    }

    #[inline]
    pub fn to_bits(self, target_size: Size) -> Result<u128, Size> {
        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
        if target_size.bytes() == u64::from(self.size) {
            self.check_data();
            Ok(self.data)
        } else {
            Err(self.size())
        }
    }
}

macro_rules! from {
    ($($ty:ty),*) => {
        $(
            impl From<$ty> for ScalarInt {
                #[inline]
                fn from(u: $ty) -> Self {
                    Self {
                        data: u128::from(u),
                        size: std::mem::size_of::<$ty>() as u8,
                    }
                }
            }
        )*
    }
}

macro_rules! try_from {
    ($($ty:ty),*) => {
        $(
            impl TryFrom<ScalarInt> for $ty {
                type Error = Size;
                #[inline]
                fn try_from(int: ScalarInt) -> Result<Self, Size> {
                    // The `unwrap` cannot fail because to_bits (if it succeeds)
                    // is guaranteed to return a value that fits into the size.
                    int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>()))
                       .map(|u| u.try_into().unwrap())
                }
            }
        )*
    }
}

from!(u8, u16, u32, u64, u128, bool);
try_from!(u8, u16, u32, u64, u128);

impl From<char> for ScalarInt {
    #[inline]
    fn from(c: char) -> Self {
        Self { data: c as u128, size: std::mem::size_of::<char>() as u8 }
    }
}

impl TryFrom<ScalarInt> for char {
    type Error = Size;
    #[inline]
    fn try_from(int: ScalarInt) -> Result<Self, Size> {
        int.to_bits(Size::from_bytes(std::mem::size_of::<char>()))
            .map(|u| char::from_u32(u.try_into().unwrap()).unwrap())
    }
}

impl From<Single> for ScalarInt {
    #[inline]
    fn from(f: Single) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { data: f.to_bits(), size: 4 }
    }
}

impl TryFrom<ScalarInt> for Single {
    type Error = Size;
    #[inline]
    fn try_from(int: ScalarInt) -> Result<Self, Size> {
        int.to_bits(Size::from_bytes(4)).map(Self::from_bits)
    }
}

impl From<Double> for ScalarInt {
    #[inline]
    fn from(f: Double) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { data: f.to_bits(), size: 8 }
    }
}

impl TryFrom<ScalarInt> for Double {
    type Error = Size;
    #[inline]
    fn try_from(int: ScalarInt) -> Result<Self, Size> {
        int.to_bits(Size::from_bytes(8)).map(Self::from_bits)
    }
}

impl fmt::Debug for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.size == 0 {
            self.check_data();
            write!(f, "<ZST>")
        } else {
            // Dispatch to LowerHex below.
            write!(f, "0x{:x}", self)
        }
    }
}

impl fmt::LowerHex for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.check_data();
        // Format as hex number wide enough to fit any value of the given `size`.
        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `write!` takes references to its formatting arguments and
        // would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB.
        write!(f, "{:01$x}", { self.data }, self.size as usize * 2)
    }
}

impl fmt::UpperHex for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.check_data();
        // Format as hex number wide enough to fit any value of the given `size`.
        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `write!` takes references to its formatting arguments and
        // would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB.
        write!(f, "{:01$X}", { self.data }, self.size as usize * 2)
    }
}
<|endoftext|>