<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Detecting language items.
//
// Language items are items that represent concepts intrinsic to the language
// itself. Examples are:
//
// * Traits that specify "kinds"; e.g. "Sync", "Send".
//
// * Traits that represent operators; e.g. "Add", "Sub", "Index".
//
// * Functions called by the compiler itself.

pub use self::LangItem::*;

use dep_graph::DepNode;
use hir::map as hir_map;
use session::Session;
use middle::cstore::CrateStore;
use hir::def_id::DefId;
use ty;
use middle::weak_lang_items;
use util::nodemap::FnvHashMap;

use syntax::ast;
use syntax::attr::AttrMetaMethods;
use syntax::parse::token::InternedString;
use hir::intravisit::Visitor;
use hir;

// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! lets_do_this {
    (
        $( $variant:ident, $name:expr, $method:ident; )*
    ) => {

enum_from_u32! {
    #[derive(Copy, Clone, PartialEq, Eq, Hash)]
    pub enum LangItem {
        $($variant,)*
    }
}

pub struct LanguageItems {
    pub items: Vec<Option<DefId>>,
    pub missing: Vec<LangItem>,
}

impl LanguageItems {
    pub fn new() -> LanguageItems {
        fn foo(_: LangItem) -> Option<DefId> { None }

        LanguageItems {
            items: vec!($(foo($variant)),*),
            missing: Vec::new(),
        }
    }

    pub fn items(&self) -> &[Option<DefId>] {
        &*self.items
    }

    pub fn item_name(index: usize) -> &'static str {
        let item: Option<LangItem> = LangItem::from_u32(index as u32);
        match item {
            $( Some($variant) => $name, )*
            None => "???"
        }
    }

    pub fn require(&self, it: LangItem) -> Result<DefId, String> {
        match self.items[it as usize] {
            Some(id) => Ok(id),
            None => {
                Err(format!("requires `{}` lang_item",
                            LanguageItems::item_name(it as usize)))
            }
        }
    }

    pub fn require_owned_box(&self) -> Result<DefId, String> {
        self.require(OwnedBoxLangItem)
    }

    pub fn from_builtin_kind(&self, bound: ty::BuiltinBound)
                             -> Result<DefId, String>
    {
        match bound {
            ty::BoundSend => self.require(SendTraitLangItem),
            ty::BoundSized => self.require(SizedTraitLangItem),
            ty::BoundCopy => self.require(CopyTraitLangItem),
            ty::BoundSync => self.require(SyncTraitLangItem),
        }
    }

    pub fn to_builtin_kind(&self, id: DefId) -> Option<ty::BuiltinBound> {
        if Some(id) == self.send_trait() {
            Some(ty::BoundSend)
        } else if Some(id) == self.sized_trait() {
            Some(ty::BoundSized)
        } else if Some(id) == self.copy_trait() {
            Some(ty::BoundCopy)
        } else if Some(id) == self.sync_trait() {
            Some(ty::BoundSync)
        } else {
            None
        }
    }

    pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
        let def_id_kinds = [
            (self.fn_trait(), ty::ClosureKind::Fn),
            (self.fn_mut_trait(), ty::ClosureKind::FnMut),
            (self.fn_once_trait(), ty::ClosureKind::FnOnce),
            ];

        for &(opt_def_id, kind) in &def_id_kinds {
            if Some(id) == opt_def_id {
                return Some(kind);
            }
        }

        None
    }

    $(
        #[allow(dead_code)]
        pub fn $method(&self) -> Option<DefId> {
            self.items[$variant as usize]
        }
    )*
}

struct LanguageItemCollector<'a, 'tcx: 'a> {
    items: LanguageItems,

    ast_map: &'a hir_map::Map<'tcx>,

    session: &'a Session,

    item_refs: FnvHashMap<&'static str, usize>,
}

impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        if let Some(value) = extract(&item.attrs) {
            let item_index = self.item_refs.get(&value[..]).cloned();

            if let Some(item_index) = item_index {
                self.collect_item(item_index, self.ast_map.local_def_id(item.id))
            } else {
                let span = self.ast_map.span(item.id);
                span_err!(self.session, span, E0522,
                          "definition of an unknown language item: `{}`.",
                          &value[..]);
            }
        }
    }
}

impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
    pub fn new(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>)
               -> LanguageItemCollector<'a, 'tcx> {
        let mut item_refs = FnvHashMap();

        $( item_refs.insert($name, $variant as usize); )*

        LanguageItemCollector {
            session: session,
            ast_map: ast_map,
            items: LanguageItems::new(),
            item_refs: item_refs,
        }
    }

    pub fn collect_item(&mut self, item_index: usize,
                        item_def_id: DefId) {
        // Check for duplicates.
        match self.items.items[item_index] {
            Some(original_def_id) if original_def_id != item_def_id => {
                let cstore = &self.session.cstore;
                let span = self.ast_map.span_if_local(item_def_id)
                                       .expect("we should have found local duplicate earlier");
                let mut err = struct_span_err!(self.session,
                                               span,
                                               E0152,
                                               "duplicate lang item found: `{}`.",
                                               LanguageItems::item_name(item_index));
                if let Some(span) = self.ast_map.span_if_local(original_def_id) {
                    span_note!(&mut err, span,
                               "first defined here.");
                } else {
                    err.note(&format!("first defined in crate `{}`.",
                                      cstore.crate_name(original_def_id.krate)));
                }
                err.emit();
            }
            _ => {
                // OK.
            }
        }

        // Matched.
        self.items.items[item_index] = Some(item_def_id);
    }

    pub fn collect_local_language_items(&mut self, krate: &hir::Crate) {
        krate.visit_all_items(self);
    }

    pub fn collect_external_language_items(&mut self) {
        let cstore = &self.session.cstore;

        for cnum in cstore.crates() {
            for (index, item_index) in cstore.lang_items(cnum) {
                let def_id = DefId { krate: cnum, index: index };
                self.collect_item(item_index, def_id);
            }
        }
    }

    pub fn collect(&mut self, krate: &hir::Crate) {
        self.collect_external_language_items();
        self.collect_local_language_items(krate);
    }
}

pub fn extract(attrs: &[ast::Attribute]) -> Option<InternedString> {
    for attribute in attrs {
        match attribute.value_str() {
            Some(ref value) if attribute.check_name("lang") => {
                return Some(value.clone());
            }
            _ => {}
        }
    }

    return None;
}

pub fn collect_language_items(session: &Session,
                              map: &hir_map::Map)
                              -> LanguageItems {
    let _task = map.dep_graph.in_task(DepNode::CollectLanguageItems);
    let krate: &hir::Crate = map.krate();
    let mut collector = LanguageItemCollector::new(session, map);
    collector.collect(krate);
    let LanguageItemCollector { mut items, .. } = collector;
    weak_lang_items::check_crate(krate, session, &mut items);
    items
}

// End of the macro
    }
}

lets_do_this! {
//  Variant name,                    Name,                      Method name;
    CharImplItem,                    "char",                    char_impl;
    StrImplItem,                     "str",                     str_impl;
    SliceImplItem,                   "slice",                   slice_impl;
    ConstPtrImplItem,                "const_ptr",               const_ptr_impl;
    MutPtrImplItem,                  "mut_ptr",                 mut_ptr_impl;
    I8ImplItem,                      "i8",                      i8_impl;
    I16ImplItem,                     "i16",                     i16_impl;
    I32ImplItem,                     "i32",                     i32_impl;
    I64ImplItem,                     "i64",                     i64_impl;
    IsizeImplItem,                   "isize",                   isize_impl;
    U8ImplItem,                      "u8",                      u8_impl;
    U16ImplItem,                     "u16",                     u16_impl;
    U32ImplItem,                     "u32",                     u32_impl;
    U64ImplItem,                     "u64",                     u64_impl;
    UsizeImplItem,                   "usize",                   usize_impl;
    F32ImplItem,                     "f32",                     f32_impl;
    F64ImplItem,                     "f64",                     f64_impl;

    SendTraitLangItem,               "send",                    send_trait;
    SizedTraitLangItem,              "sized",                   sized_trait;
    UnsizeTraitLangItem,             "unsize",                  unsize_trait;
    CopyTraitLangItem,               "copy",                    copy_trait;
    SyncTraitLangItem,               "sync",                    sync_trait;

    DropTraitLangItem,               "drop",                    drop_trait;

    CoerceUnsizedTraitLangItem,      "coerce_unsized",          coerce_unsized_trait;

    AddTraitLangItem,                "add",                     add_trait;
    SubTraitLangItem,                "sub",                     sub_trait;
    MulTraitLangItem,                "mul",                     mul_trait;
    DivTraitLangItem,                "div",                     div_trait;
    RemTraitLangItem,                "rem",                     rem_trait;
    NegTraitLangItem,                "neg",                     neg_trait;
    NotTraitLangItem,                "not",                     not_trait;
    BitXorTraitLangItem,             "bitxor",                  bitxor_trait;
    BitAndTraitLangItem,             "bitand",                  bitand_trait;
    BitOrTraitLangItem,              "bitor",                   bitor_trait;
    ShlTraitLangItem,                "shl",                     shl_trait;
    ShrTraitLangItem,                "shr",                     shr_trait;
    AddAssignTraitLangItem,          "add_assign",              add_assign_trait;
    SubAssignTraitLangItem,          "sub_assign",              sub_assign_trait;
    MulAssignTraitLangItem,          "mul_assign",              mul_assign_trait;
    DivAssignTraitLangItem,          "div_assign",              div_assign_trait;
    RemAssignTraitLangItem,          "rem_assign",              rem_assign_trait;
    BitXorAssignTraitLangItem,       "bitxor_assign",           bitxor_assign_trait;
    BitAndAssignTraitLangItem,       "bitand_assign",           bitand_assign_trait;
    BitOrAssignTraitLangItem,        "bitor_assign",            bitor_assign_trait;
    ShlAssignTraitLangItem,          "shl_assign",              shl_assign_trait;
    ShrAssignTraitLangItem,          "shr_assign",              shr_assign_trait;
    IndexTraitLangItem,              "index",                   index_trait;
    IndexMutTraitLangItem,           "index_mut",               index_mut_trait;

    UnsafeCellTypeLangItem,          "unsafe_cell",             unsafe_cell_type;

    DerefTraitLangItem,              "deref",                   deref_trait;
    DerefMutTraitLangItem,           "deref_mut",               deref_mut_trait;

    FnTraitLangItem,                 "fn",                      fn_trait;
    FnMutTraitLangItem,              "fn_mut",                  fn_mut_trait;
    FnOnceTraitLangItem,             "fn_once",                 fn_once_trait;

    EqTraitLangItem,                 "eq",                      eq_trait;
    OrdTraitLangItem,                "ord",                     ord_trait;

    StrEqFnLangItem,                 "str_eq",                  str_eq_fn;

    // A number of panic-related lang items. The `panic` item corresponds to
    // divide-by-zero and various panic cases with `match`. The
    // `panic_bounds_check` item is for indexing arrays.
    //
    // The `begin_unwind` lang item has a predefined symbol name and is sort of
    // a "weak lang item" in the sense that a crate is not required to have it
    // defined to use it, but a final product is required to define it
    // somewhere. Additionally, there are restrictions on crates that use a weak
    // lang item, but do not have it defined.
    PanicFnLangItem,                 "panic",                   panic_fn;
    PanicBoundsCheckFnLangItem,      "panic_bounds_check",      panic_bounds_check_fn;
    PanicFmtLangItem,                "panic_fmt",               panic_fmt;

    ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
    ExchangeFreeFnLangItem,          "exchange_free",           exchange_free_fn;
    BoxFreeFnLangItem,               "box_free",                box_free_fn;
    StrDupUniqFnLangItem,            "strdup_uniq",             strdup_uniq_fn;

    StartFnLangItem,                 "start",                   start_fn;

    EhPersonalityLangItem,           "eh_personality",          eh_personality;
    EhPersonalityCatchLangItem,      "eh_personality_catch",    eh_personality_catch;
    EhUnwindResumeLangItem,          "eh_unwind_resume",        eh_unwind_resume;
    MSVCTryFilterLangItem,           "msvc_try_filter",         msvc_try_filter;

    OwnedBoxLangItem,                "owned_box",               owned_box;

    PhantomDataItem,                 "phantom_data",            phantom_data;

    // Deprecated:
    CovariantTypeItem,               "covariant_type",          covariant_type;
    ContravariantTypeItem,           "contravariant_type",      contravariant_type;
    InvariantTypeItem,               "invariant_type",          invariant_type;
    CovariantLifetimeItem,           "covariant_lifetime",      covariant_lifetime;
    ContravariantLifetimeItem,       "contravariant_lifetime",  contravariant_lifetime;
    InvariantLifetimeItem,           "invariant_lifetime",      invariant_lifetime;

    NoCopyItem,                      "no_copy_bound",           no_copy_bound;

    NonZeroItem,                     "non_zero",                non_zero;

    DebugTraitLangItem,              "debug_trait",             debug_trait;
}
<commit_msg>Accommodate the case where dup lang items are entirely external.<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Detecting language items.
//
// Language items are items that represent concepts intrinsic to the language
// itself. Examples are:
//
// * Traits that specify "kinds"; e.g. "Sync", "Send".
//
// * Traits that represent operators; e.g. "Add", "Sub", "Index".
//
// * Functions called by the compiler itself.

pub use self::LangItem::*;

use dep_graph::DepNode;
use hir::map as hir_map;
use session::Session;
use middle::cstore::CrateStore;
use hir::def_id::DefId;
use ty;
use middle::weak_lang_items;
use util::nodemap::FnvHashMap;

use syntax::ast;
use syntax::attr::AttrMetaMethods;
use syntax::parse::token::InternedString;
use hir::intravisit::Visitor;
use hir;

// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! lets_do_this {
    (
        $( $variant:ident, $name:expr, $method:ident; )*
    ) => {

enum_from_u32! {
    #[derive(Copy, Clone, PartialEq, Eq, Hash)]
    pub enum LangItem {
        $($variant,)*
    }
}

pub struct LanguageItems {
    pub items: Vec<Option<DefId>>,
    pub missing: Vec<LangItem>,
}

impl LanguageItems {
    pub fn new() -> LanguageItems {
        fn foo(_: LangItem) -> Option<DefId> { None }

        LanguageItems {
            items: vec!($(foo($variant)),*),
            missing: Vec::new(),
        }
    }

    pub fn items(&self) -> &[Option<DefId>] {
        &*self.items
    }

    pub fn item_name(index: usize) -> &'static str {
        let item: Option<LangItem> = LangItem::from_u32(index as u32);
        match item {
            $( Some($variant) => $name, )*
            None => "???"
        }
    }

    pub fn require(&self, it: LangItem) -> Result<DefId, String> {
        match self.items[it as usize] {
            Some(id) => Ok(id),
            None => {
                Err(format!("requires `{}` lang_item",
                            LanguageItems::item_name(it as usize)))
            }
        }
    }

    pub fn require_owned_box(&self) -> Result<DefId, String> {
        self.require(OwnedBoxLangItem)
    }

    pub fn from_builtin_kind(&self, bound: ty::BuiltinBound)
                             -> Result<DefId, String>
    {
        match bound {
            ty::BoundSend => self.require(SendTraitLangItem),
            ty::BoundSized => self.require(SizedTraitLangItem),
            ty::BoundCopy => self.require(CopyTraitLangItem),
            ty::BoundSync => self.require(SyncTraitLangItem),
        }
    }

    pub fn to_builtin_kind(&self, id: DefId) -> Option<ty::BuiltinBound> {
        if Some(id) == self.send_trait() {
            Some(ty::BoundSend)
        } else if Some(id) == self.sized_trait() {
            Some(ty::BoundSized)
        } else if Some(id) == self.copy_trait() {
            Some(ty::BoundCopy)
        } else if Some(id) == self.sync_trait() {
            Some(ty::BoundSync)
        } else {
            None
        }
    }

    pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
        let def_id_kinds = [
            (self.fn_trait(), ty::ClosureKind::Fn),
            (self.fn_mut_trait(), ty::ClosureKind::FnMut),
            (self.fn_once_trait(), ty::ClosureKind::FnOnce),
            ];

        for &(opt_def_id, kind) in &def_id_kinds {
            if Some(id) == opt_def_id {
                return Some(kind);
            }
        }

        None
    }

    $(
        #[allow(dead_code)]
        pub fn $method(&self) -> Option<DefId> {
            self.items[$variant as usize]
        }
    )*
}

struct LanguageItemCollector<'a, 'tcx: 'a> {
    items: LanguageItems,

    ast_map: &'a hir_map::Map<'tcx>,

    session: &'a Session,

    item_refs: FnvHashMap<&'static str, usize>,
}

impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        if let Some(value) = extract(&item.attrs) {
            let item_index = self.item_refs.get(&value[..]).cloned();

            if let Some(item_index) = item_index {
                self.collect_item(item_index, self.ast_map.local_def_id(item.id))
            } else {
                let span = self.ast_map.span(item.id);
                span_err!(self.session, span, E0522,
                          "definition of an unknown language item: `{}`.",
                          &value[..]);
            }
        }
    }
}

impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
    pub fn new(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>)
               -> LanguageItemCollector<'a, 'tcx> {
        let mut item_refs = FnvHashMap();

        $( item_refs.insert($name, $variant as usize); )*

        LanguageItemCollector {
            session: session,
            ast_map: ast_map,
            items: LanguageItems::new(),
            item_refs: item_refs,
        }
    }

    pub fn collect_item(&mut self, item_index: usize,
                        item_def_id: DefId) {
        // Check for duplicates.
        match self.items.items[item_index] {
            Some(original_def_id) if original_def_id != item_def_id => {
                let cstore = &self.session.cstore;
                let name = LanguageItems::item_name(item_index);
                let mut err = match self.ast_map.span_if_local(item_def_id) {
                    Some(span) => struct_span_err!(
                        self.session,
                        span,
                        E0152,
                        "duplicate lang item found: `{}`.",
                        name),
                    None => self.session.struct_err(&format!(
                            "duplicate lang item in crate `{}`: `{}`.",
                            cstore.crate_name(item_def_id.krate),
                            name)),
                };
                if let Some(span) = self.ast_map.span_if_local(original_def_id) {
                    span_note!(&mut err, span,
                               "first defined here.");
                } else {
                    err.note(&format!("first defined in crate `{}`.",
                                      cstore.crate_name(original_def_id.krate)));
                }
                err.emit();
            }
            _ => {
                // OK.
            }
        }

        // Matched.
        self.items.items[item_index] = Some(item_def_id);
    }

    pub fn collect_local_language_items(&mut self, krate: &hir::Crate) {
        krate.visit_all_items(self);
    }

    pub fn collect_external_language_items(&mut self) {
        let cstore = &self.session.cstore;

        for cnum in cstore.crates() {
            for (index, item_index) in cstore.lang_items(cnum) {
                let def_id = DefId { krate: cnum, index: index };
                self.collect_item(item_index, def_id);
            }
        }
    }

    pub fn collect(&mut self, krate: &hir::Crate) {
        self.collect_external_language_items();
        self.collect_local_language_items(krate);
    }
}

pub fn extract(attrs: &[ast::Attribute]) -> Option<InternedString> {
    for attribute in attrs {
        match attribute.value_str() {
            Some(ref value) if attribute.check_name("lang") => {
                return Some(value.clone());
            }
            _ => {}
        }
    }

    return None;
}

pub fn collect_language_items(session: &Session,
                              map: &hir_map::Map)
                              -> LanguageItems {
    let _task = map.dep_graph.in_task(DepNode::CollectLanguageItems);
    let krate: &hir::Crate = map.krate();
    let mut collector = LanguageItemCollector::new(session, map);
    collector.collect(krate);
    let LanguageItemCollector { mut items, .. } = collector;
    weak_lang_items::check_crate(krate, session, &mut items);
    items
}

// End of the macro
    }
}

lets_do_this! {
//  Variant name,                    Name,                      Method name;
    CharImplItem,                    "char",                    char_impl;
    StrImplItem,                     "str",                     str_impl;
    SliceImplItem,                   "slice",                   slice_impl;
    ConstPtrImplItem,                "const_ptr",               const_ptr_impl;
    MutPtrImplItem,                  "mut_ptr",                 mut_ptr_impl;
    I8ImplItem,                      "i8",                      i8_impl;
    I16ImplItem,                     "i16",                     i16_impl;
    I32ImplItem,                     "i32",                     i32_impl;
    I64ImplItem,                     "i64",                     i64_impl;
    IsizeImplItem,                   "isize",                   isize_impl;
    U8ImplItem,                      "u8",                      u8_impl;
    U16ImplItem,                     "u16",                     u16_impl;
    U32ImplItem,                     "u32",                     u32_impl;
    U64ImplItem,                     "u64",                     u64_impl;
    UsizeImplItem,                   "usize",                   usize_impl;
    F32ImplItem,                     "f32",                     f32_impl;
    F64ImplItem,                     "f64",                     f64_impl;

    SendTraitLangItem,               "send",                    send_trait;
    SizedTraitLangItem,              "sized",                   sized_trait;
    UnsizeTraitLangItem,             "unsize",                  unsize_trait;
    CopyTraitLangItem,               "copy",                    copy_trait;
    SyncTraitLangItem,               "sync",                    sync_trait;

    DropTraitLangItem,               "drop",                    drop_trait;

    CoerceUnsizedTraitLangItem,      "coerce_unsized",          coerce_unsized_trait;

    AddTraitLangItem,                "add",                     add_trait;
    SubTraitLangItem,                "sub",                     sub_trait;
    MulTraitLangItem,                "mul",                     mul_trait;
    DivTraitLangItem,                "div",                     div_trait;
    RemTraitLangItem,                "rem",                     rem_trait;
    NegTraitLangItem,                "neg",                     neg_trait;
    NotTraitLangItem,                "not",                     not_trait;
    BitXorTraitLangItem,             "bitxor",                  bitxor_trait;
    BitAndTraitLangItem,             "bitand",                  bitand_trait;
    BitOrTraitLangItem,              "bitor",                   bitor_trait;
    ShlTraitLangItem,                "shl",                     shl_trait;
    ShrTraitLangItem,                "shr",                     shr_trait;
    AddAssignTraitLangItem,          "add_assign",              add_assign_trait;
    SubAssignTraitLangItem,          "sub_assign",              sub_assign_trait;
    MulAssignTraitLangItem,          "mul_assign",              mul_assign_trait;
    DivAssignTraitLangItem,          "div_assign",              div_assign_trait;
    RemAssignTraitLangItem,          "rem_assign",              rem_assign_trait;
    BitXorAssignTraitLangItem,       "bitxor_assign",           bitxor_assign_trait;
    BitAndAssignTraitLangItem,       "bitand_assign",           bitand_assign_trait;
    BitOrAssignTraitLangItem,        "bitor_assign",            bitor_assign_trait;
    ShlAssignTraitLangItem,          "shl_assign",              shl_assign_trait;
    ShrAssignTraitLangItem,          "shr_assign",              shr_assign_trait;
    IndexTraitLangItem,              "index",                   index_trait;
    IndexMutTraitLangItem,           "index_mut",               index_mut_trait;

    UnsafeCellTypeLangItem,          "unsafe_cell",             unsafe_cell_type;

    DerefTraitLangItem,              "deref",                   deref_trait;
    DerefMutTraitLangItem,           "deref_mut",               deref_mut_trait;

    FnTraitLangItem,                 "fn",                      fn_trait;
    FnMutTraitLangItem,              "fn_mut",                  fn_mut_trait;
    FnOnceTraitLangItem,             "fn_once",                 fn_once_trait;

    EqTraitLangItem,                 "eq",                      eq_trait;
    OrdTraitLangItem,                "ord",                     ord_trait;

    StrEqFnLangItem,                 "str_eq",                  str_eq_fn;

    // A number of panic-related lang items. The `panic` item corresponds to
    // divide-by-zero and various panic cases with `match`. The
    // `panic_bounds_check` item is for indexing arrays.
    //
    // The `begin_unwind` lang item has a predefined symbol name and is sort of
    // a "weak lang item" in the sense that a crate is not required to have it
    // defined to use it, but a final product is required to define it
    // somewhere. Additionally, there are restrictions on crates that use a weak
    // lang item, but do not have it defined.
    PanicFnLangItem,                 "panic",                   panic_fn;
    PanicBoundsCheckFnLangItem,      "panic_bounds_check",      panic_bounds_check_fn;
    PanicFmtLangItem,                "panic_fmt",               panic_fmt;

    ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
    ExchangeFreeFnLangItem,          "exchange_free",           exchange_free_fn;
    BoxFreeFnLangItem,               "box_free",                box_free_fn;
    StrDupUniqFnLangItem,            "strdup_uniq",             strdup_uniq_fn;

    StartFnLangItem,                 "start",                   start_fn;

    EhPersonalityLangItem,           "eh_personality",          eh_personality;
    EhPersonalityCatchLangItem,      "eh_personality_catch",    eh_personality_catch;
    EhUnwindResumeLangItem,          "eh_unwind_resume",        eh_unwind_resume;
    MSVCTryFilterLangItem,           "msvc_try_filter",         msvc_try_filter;

    OwnedBoxLangItem,                "owned_box",               owned_box;

    PhantomDataItem,                 "phantom_data",            phantom_data;

    // Deprecated:
    CovariantTypeItem,               "covariant_type",          covariant_type;
    ContravariantTypeItem,           "contravariant_type",      contravariant_type;
    InvariantTypeItem,               "invariant_type",          invariant_type;
    CovariantLifetimeItem,           "covariant_lifetime",      covariant_lifetime;
    ContravariantLifetimeItem,       "contravariant_lifetime",  contravariant_lifetime;
    InvariantLifetimeItem,           "invariant_lifetime",      invariant_lifetime;

    NoCopyItem,                      "no_copy_bound",           no_copy_bound;

    NonZeroItem,                     "non_zero",                non_zero;

    DebugTraitLangItem,              "debug_trait",             debug_trait;
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An interpreter for MIR used in CTFE and by miri

mod cast;
mod eval_context;
mod place;
mod operand;
mod machine;
mod memory;
mod operator;
pub(crate) mod snapshot; // for const_eval
mod step;
mod terminator;
mod traits;
mod validity;
mod intrinsics;
mod visitor;

pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here

pub use self::eval_context::{
    EvalContext, Frame, StackPopCleanup, LocalValue,
};

pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};

pub use self::memory::{Memory, MemoryKind};

pub use self::machine::{Machine, AllocMap, MayLeak};

pub use self::operand::{ScalarMaybeUndef, Immediate, ImmTy, Operand, OpTy};

pub use self::visitor::ValueVisitor;

pub use self::validity::RefTracking;
<commit_msg>expose MutValueVisitor<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An interpreter for MIR used in CTFE and by miri

mod cast;
mod eval_context;
mod place;
mod operand;
mod machine;
mod memory;
mod operator;
pub(crate) mod snapshot; // for const_eval
mod step;
mod terminator;
mod traits;
mod validity;
mod intrinsics;
mod visitor;

pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here

pub use self::eval_context::{
    EvalContext, Frame, StackPopCleanup, LocalValue,
};

pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};

pub use self::memory::{Memory, MemoryKind};

pub use self::machine::{Machine, AllocMap, MayLeak};

pub use self::operand::{ScalarMaybeUndef, Immediate, ImmTy, Operand, OpTy};

pub use self::visitor::{ValueVisitor, MutValueVisitor};

pub use self::validity::RefTracking;
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use llvm::ValueRef;
use rustc::ty::Ty;
use rustc::mir::repr as mir;
use rustc_data_structures::indexed_vec::Idx;

use base;
use common::{self, Block, BlockAndBuilder};
use value::Value;
use type_of;
use type_::Type;

use std::fmt;

use super::{MirContext, TempRef};

/// The representation of a Rust value. The enum variant is in fact
/// uniquely determined by the value's type, but is kept as a
/// safety check.
#[derive(Copy, Clone)]
pub enum OperandValue {
    /// A reference to the actual operand. The data is guaranteed
    /// to be valid for the operand's lifetime.
    Ref(ValueRef),
    /// A single LLVM value.
    Immediate(ValueRef),
    /// A pair of immediate LLVM values. Used by fat pointers too.
    Pair(ValueRef, ValueRef)
}

/// An `OperandRef` is an "SSA" reference to a Rust value, along with
/// its type.
///
/// NOTE: unless you know a value's type exactly, you should not
/// generate LLVM opcodes acting on it and instead act via methods,
/// to avoid nasty edge cases. In particular, using `Builder.store`
/// directly is sure to cause problems -- use `MirContext.store_operand`
/// instead.
#[derive(Copy, Clone)]
pub struct OperandRef<'tcx> {
    // The value.
    pub val: OperandValue,

    // The type of value being returned.
    pub ty: Ty<'tcx>
}

impl<'tcx> fmt::Debug for OperandRef<'tcx> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.val {
            OperandValue::Ref(r) => {
                write!(f, "OperandRef(Ref({:?}) @ {:?})",
                       Value(r), self.ty)
            }
            OperandValue::Immediate(i) => {
                write!(f, "OperandRef(Immediate({:?}) @ {:?})",
                       Value(i), self.ty)
            }
            OperandValue::Pair(a, b) => {
                write!(f, "OperandRef(Pair({:?}, {:?}) @ {:?})",
                       Value(a), Value(b), self.ty)
            }
        }
    }
}

impl<'bcx, 'tcx> OperandRef<'tcx> {
    /// Asserts that this operand refers to a scalar and returns
    /// a reference to its value.
    pub fn immediate(self) -> ValueRef {
        match self.val {
            OperandValue::Immediate(s) => s,
            _ => bug!()
        }
    }

    /// If this operand is a Pair, we return an
    /// Immediate aggregate with the two values.
    pub fn pack_if_pair(mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>)
                        -> OperandRef<'tcx> {
        if let OperandValue::Pair(a, b) = self.val {
            // Reconstruct the immediate aggregate.
            let llty = type_of::type_of(bcx.ccx(), self.ty);
            let mut llpair = common::C_undef(llty);
            let elems = [a, b];
            for i in 0..2 {
                let mut elem = elems[i];
                // Extend boolean i1's to i8.
                if common::val_ty(elem) == Type::i1(bcx.ccx()) {
                    elem = bcx.zext(elem, Type::i8(bcx.ccx()));
                }
                llpair = bcx.insert_value(llpair, elem, i);
            }
            self.val = OperandValue::Immediate(llpair);
        }
        self
    }

    /// If this operand is a pair in an Immediate,
    /// we return a Pair with the two halves.
    pub fn unpack_if_pair(mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>)
                          -> OperandRef<'tcx> {
        if let OperandValue::Immediate(llval) = self.val {
            // Deconstruct the immediate aggregate.
            if common::type_is_imm_pair(bcx.ccx(), self.ty) {
                let mut a = bcx.extract_value(llval, 0);
                let mut b = bcx.extract_value(llval, 1);

                let pair_fields = common::type_pair_fields(bcx.ccx(), self.ty);
                if let Some([a_ty, b_ty]) = pair_fields {
                    if a_ty.is_bool() {
                        a = bcx.trunc(a, Type::i1(bcx.ccx()));
                    }
                    if b_ty.is_bool() {
                        b = bcx.trunc(b, Type::i1(bcx.ccx()));
                    }
                }

                self.val = OperandValue::Pair(a, b);
            }
        }
        self
    }
}

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
    pub fn trans_load(&mut self,
                      bcx: &BlockAndBuilder<'bcx, 'tcx>,
                      llval: ValueRef,
                      ty: Ty<'tcx>)
                      -> OperandRef<'tcx>
    {
        debug!("trans_load: {:?} @ {:?}", Value(llval), ty);

        let val = if common::type_is_imm_pair(bcx.ccx(), ty) {
            let a_ptr = bcx.struct_gep(llval, 0);
            let b_ptr = bcx.struct_gep(llval, 1);

            // This is None only for fat pointers, which don't
            // need any special load-time behavior anyway.
            let pair_fields = common::type_pair_fields(bcx.ccx(), ty);
            let (a, b) = if let Some([a_ty, b_ty]) = pair_fields {
                (base::load_ty_builder(bcx, a_ptr, a_ty),
                 base::load_ty_builder(bcx, b_ptr, b_ty))
            } else {
                (bcx.load(a_ptr), bcx.load(b_ptr))
            };
            OperandValue::Pair(a, b)
        } else if common::type_is_immediate(bcx.ccx(), ty) {
            OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty))
        } else {
            OperandValue::Ref(llval)
        };

        OperandRef { val: val, ty: ty }
    }

    pub fn trans_operand(&mut self,
                         bcx: &BlockAndBuilder<'bcx, 'tcx>,
                         operand: &mir::Operand<'tcx>)
                         -> OperandRef<'tcx>
    {
        debug!("trans_operand(operand={:?})", operand);

        match *operand {
            mir::Operand::Consume(ref lvalue) => {
                // watch out for temporaries that do not have an
                // alloca; they are handled somewhat differently
                if let &mir::Lvalue::Temp(index) = lvalue {
                    match self.temps[index] {
                        TempRef::Operand(Some(o)) => {
                            return o;
                        }
                        TempRef::Operand(None) => {
                            bug!("use of {:?} before def", lvalue);
                        }
                        TempRef::Lvalue(..) => {
                            // use path below
                        }
                    }
                }

                // Moves out of pair fields are trivial.
                if let &mir::Lvalue::Projection(ref proj) = lvalue {
                    if let mir::Lvalue::Temp(index) = proj.base {
                        let temp_ref = &self.temps[index];
                        if let &TempRef::Operand(Some(o)) = temp_ref {
                            match (o.val, &proj.elem) {
                                (OperandValue::Pair(a, b),
                                 &mir::ProjectionElem::Field(ref f, ty)) => {
                                    let llval = [a, b][f.index()];
                                    return OperandRef {
                                        val: OperandValue::Immediate(llval),
                                        ty: bcx.monomorphize(&ty)
                                    };
                                }
                                _ => {}
                            }
                        }
                    }
                }

                // for most lvalues, to consume them we just load them
                // out from their home
                let tr_lvalue = self.trans_lvalue(bcx, lvalue);
                let ty = tr_lvalue.ty.to_ty(bcx.tcx());
                self.trans_load(bcx, tr_lvalue.llval, ty)
            }

            mir::Operand::Constant(ref constant) => {
                let val = self.trans_constant(bcx, constant);
                let operand = val.to_operand(bcx.ccx());
                if let OperandValue::Ref(ptr) = operand.val {
                    // If this is a OperandValue::Ref to an immediate constant, load it.
                    self.trans_load(bcx, ptr, operand.ty)
                } else {
                    operand
                }
            }
        }
    }

    pub fn store_operand(&mut self,
                         bcx: &BlockAndBuilder<'bcx, 'tcx>,
                         lldest: ValueRef,
                         operand: OperandRef<'tcx>)
    {
        debug!("store_operand: operand={:?}", operand);
        bcx.with_block(|bcx| self.store_operand_direct(bcx, lldest, operand))
    }

    pub fn store_operand_direct(&mut self,
                                bcx: Block<'bcx, 'tcx>,
                                lldest: ValueRef,
                                operand: OperandRef<'tcx>)
    {
        // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
        // value is through `undef`, and store itself is useless.
        if common::type_is_zero_size(bcx.ccx(), operand.ty) {
            return;
        }
        match operand.val {
            OperandValue::Ref(r) => base::memcpy_ty(bcx, lldest, r, operand.ty),
            OperandValue::Immediate(s) => base::store_ty(bcx, s, lldest, operand.ty),
            OperandValue::Pair(a, b) => {
                use build::*;
                let a = base::from_immediate(bcx, a);
                let b = base::from_immediate(bcx, b);
                Store(bcx, a, StructGEP(bcx, lldest, 0));
                Store(bcx, b, StructGEP(bcx, lldest, 1));
            }
        }
    }
}
<commit_msg>trans: split trans_consume off from trans_operand.<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use llvm::ValueRef;
use rustc::ty::Ty;
use rustc::mir::repr as mir;
use rustc_data_structures::indexed_vec::Idx;

use base;
use common::{self, Block, BlockAndBuilder};
use value::Value;
use type_of;
use type_::Type;

use std::fmt;

use super::{MirContext, TempRef};

/// The representation of a Rust value. The enum variant is in fact
/// uniquely determined by the value's type, but is kept as a
/// safety check.
#[derive(Copy, Clone)]
pub enum OperandValue {
    /// A reference to the actual operand. The data is guaranteed
    /// to be valid for the operand's lifetime.
    Ref(ValueRef),
    /// A single LLVM value.
    Immediate(ValueRef),
    /// A pair of immediate LLVM values. Used by fat pointers too.
    Pair(ValueRef, ValueRef)
}

/// An `OperandRef` is an "SSA" reference to a Rust value, along with
/// its type.
///
/// NOTE: unless you know a value's type exactly, you should not
/// generate LLVM opcodes acting on it and instead act via methods,
/// to avoid nasty edge cases. In particular, using `Builder.store`
/// directly is sure to cause problems -- use `MirContext.store_operand`
/// instead.
#[derive(Copy, Clone)]
pub struct OperandRef<'tcx> {
    // The value.
    pub val: OperandValue,

    // The type of value being returned.
    pub ty: Ty<'tcx>
}

impl<'tcx> fmt::Debug for OperandRef<'tcx> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.val {
            OperandValue::Ref(r) => {
                write!(f, "OperandRef(Ref({:?}) @ {:?})",
                       Value(r), self.ty)
            }
            OperandValue::Immediate(i) => {
                write!(f, "OperandRef(Immediate({:?}) @ {:?})",
                       Value(i), self.ty)
            }
            OperandValue::Pair(a, b) => {
                write!(f, "OperandRef(Pair({:?}, {:?}) @ {:?})",
                       Value(a), Value(b), self.ty)
            }
        }
    }
}

impl<'bcx, 'tcx> OperandRef<'tcx> {
    /// Asserts that this operand refers to a scalar and returns
    /// a reference to its value.
    pub fn immediate(self) -> ValueRef {
        match self.val {
            OperandValue::Immediate(s) => s,
            _ => bug!()
        }
    }

    /// If this operand is a Pair, we return an
    /// Immediate aggregate with the two values.
    pub fn pack_if_pair(mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>)
                        -> OperandRef<'tcx> {
        if let OperandValue::Pair(a, b) = self.val {
            // Reconstruct the immediate aggregate.
            let llty = type_of::type_of(bcx.ccx(), self.ty);
            let mut llpair = common::C_undef(llty);
            let elems = [a, b];
            for i in 0..2 {
                let mut elem = elems[i];
                // Extend boolean i1's to i8.
                if common::val_ty(elem) == Type::i1(bcx.ccx()) {
                    elem = bcx.zext(elem, Type::i8(bcx.ccx()));
                }
                llpair = bcx.insert_value(llpair, elem, i);
            }
            self.val = OperandValue::Immediate(llpair);
        }
        self
    }

    /// If this operand is a pair in an Immediate,
    /// we return a Pair with the two halves.
    pub fn unpack_if_pair(mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>)
                          -> OperandRef<'tcx> {
        if let OperandValue::Immediate(llval) = self.val {
            // Deconstruct the immediate aggregate.
            if common::type_is_imm_pair(bcx.ccx(), self.ty) {
                let mut a = bcx.extract_value(llval, 0);
                let mut b = bcx.extract_value(llval, 1);

                let pair_fields = common::type_pair_fields(bcx.ccx(), self.ty);
                if let Some([a_ty, b_ty]) = pair_fields {
                    if a_ty.is_bool() {
                        a = bcx.trunc(a, Type::i1(bcx.ccx()));
                    }
                    if b_ty.is_bool() {
                        b = bcx.trunc(b, Type::i1(bcx.ccx()));
                    }
                }

                self.val = OperandValue::Pair(a, b);
            }
        }
        self
    }
}

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
    pub fn trans_load(&mut self,
                      bcx: &BlockAndBuilder<'bcx, 'tcx>,
                      llval: ValueRef,
                      ty: Ty<'tcx>)
                      -> OperandRef<'tcx>
    {
        debug!("trans_load: {:?} @ {:?}", Value(llval), ty);

        let val = if common::type_is_imm_pair(bcx.ccx(), ty) {
            let a_ptr = bcx.struct_gep(llval, 0);
            let b_ptr = bcx.struct_gep(llval, 1);

            // This is None only for fat pointers, which don't
            // need any special load-time behavior anyway.
            let pair_fields = common::type_pair_fields(bcx.ccx(), ty);
            let (a, b) = if let Some([a_ty, b_ty]) = pair_fields {
                (base::load_ty_builder(bcx, a_ptr, a_ty),
                 base::load_ty_builder(bcx, b_ptr, b_ty))
            } else {
                (bcx.load(a_ptr), bcx.load(b_ptr))
            };
            OperandValue::Pair(a, b)
        } else if common::type_is_immediate(bcx.ccx(), ty) {
            OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty))
        } else {
            OperandValue::Ref(llval)
        };

        OperandRef { val: val, ty: ty }
    }

    pub fn trans_consume(&mut self,
                         bcx: &BlockAndBuilder<'bcx, 'tcx>,
                         lvalue: &mir::Lvalue<'tcx>)
                         -> OperandRef<'tcx>
    {
        debug!("trans_consume(lvalue={:?})", lvalue);

        // watch out for temporaries that do not have an
        // alloca; they are handled somewhat differently
        if let &mir::Lvalue::Temp(index) = lvalue {
            match self.temps[index] {
                TempRef::Operand(Some(o)) => {
                    return o;
                }
                TempRef::Operand(None) => {
                    bug!("use of {:?} before def", lvalue);
                }
                TempRef::Lvalue(..) => {
                    // use path below
                }
            }
        }

        // Moves out of pair fields are trivial.
        if let &mir::Lvalue::Projection(ref proj) = lvalue {
            if let mir::Lvalue::Temp(index) = proj.base {
                let temp_ref = &self.temps[index];
                if let &TempRef::Operand(Some(o)) = temp_ref {
                    match (o.val, &proj.elem) {
                        (OperandValue::Pair(a, b),
                         &mir::ProjectionElem::Field(ref f, ty)) => {
                            let llval = [a, b][f.index()];
                            return OperandRef {
                                val: OperandValue::Immediate(llval),
                                ty: bcx.monomorphize(&ty)
                            };
                        }
                        _ => {}
                    }
                }
            }
        }

        // for most lvalues, to consume them we just load them
        // out from their home
        let tr_lvalue = self.trans_lvalue(bcx, lvalue);
        let ty = tr_lvalue.ty.to_ty(bcx.tcx());
        self.trans_load(bcx, tr_lvalue.llval, ty)
    }

    pub fn trans_operand(&mut self,
                         bcx: &BlockAndBuilder<'bcx, 'tcx>,
                         operand: &mir::Operand<'tcx>)
                         -> OperandRef<'tcx>
    {
        debug!("trans_operand(operand={:?})", operand);

        match *operand {
            mir::Operand::Consume(ref lvalue) => {
                self.trans_consume(bcx, lvalue)
            }

            mir::Operand::Constant(ref constant) => {
                let val = self.trans_constant(bcx, constant);
                let operand = val.to_operand(bcx.ccx());
                if let OperandValue::Ref(ptr) = operand.val {
                    // If this is a OperandValue::Ref to an immediate constant, load it.
                    self.trans_load(bcx, ptr, operand.ty)
                } else {
                    operand
                }
            }
        }
    }

    pub fn store_operand(&mut self,
                         bcx: &BlockAndBuilder<'bcx, 'tcx>,
                         lldest: ValueRef,
                         operand: OperandRef<'tcx>)
    {
        debug!("store_operand: operand={:?}", operand);
        bcx.with_block(|bcx| self.store_operand_direct(bcx, lldest, operand))
    }

    pub fn store_operand_direct(&mut self,
                                bcx: Block<'bcx, 'tcx>,
                                lldest: ValueRef,
                                operand: OperandRef<'tcx>)
    {
        // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
        // value is through `undef`, and store itself is useless.
        if common::type_is_zero_size(bcx.ccx(), operand.ty) {
            return;
        }
        match operand.val {
            OperandValue::Ref(r) => base::memcpy_ty(bcx, lldest, r, operand.ty),
            OperandValue::Immediate(s) => base::store_ty(bcx, s, lldest, operand.ty),
            OperandValue::Pair(a, b) => {
                use build::*;
                let a = base::from_immediate(bcx, a);
                let b = base::from_immediate(bcx, b);
                Store(bcx, a, StructGEP(bcx, lldest, 0));
                Store(bcx, b, StructGEP(bcx, lldest, 1));
            }
        }
    }
}
<|endoftext|>


<commit_before>use netinfo::{Pid, PacketInfo, CaptureHandle, PacketMatcher, InoutType, TransportType, NetworkInterface, StopRequest};
use pnet::datalink::NetworkInterface as PnetNetworkInterface;
use std::sync::Arc;
use std::sync::Mutex;
use std::collections::HashMap;
use std::thread;
use std::thread::{JoinHandle};
use netinfo::error::*;

#[derive(Clone, Debug, Default)]
/// Contains detailed information on network usage on per attribute (pid, in/out, tcp/udp).
pub struct NetStatistics {
    /// Usage per "Pid | Inout | Udp/Tcp". Some values might not be known (we know a package is tcp-outgoing but can't
    /// figure out an associated process).
    map: HashMap<(Option<Pid>, Option<InoutType>, Option<TransportType>), u64>,
}

impl NetStatistics {
    fn add_bytes(&mut self, pid: Option<Pid>, c: Option<InoutType>, tt: Option<TransportType>, b: u64) {
        *self.map.entry((pid, c, tt)).or_insert(0) += b;
    }

    /// None means "this value can be arbitrary".
    fn get_bytes_by_filter(&self, pid: Option<Pid>, c: Option<InoutType>, tt: Option<TransportType>) -> u64 {
        self.map.iter()
                .filter(|&(&(kpid, kc, ktt), _)| (pid == None || pid == kpid) && (c == None || c == kc) && (tt == None || tt == ktt))
                .map(|(_, &b)| b)
                .fold(0, |b, acc| b + acc)
    }

    /// Get network usage per pid.
    pub fn get_bytes_by_pid(&self, pid: Pid) -> u64 {
        self.get_bytes_by_attr(Some(pid), None, None)
    }

    /// Get network usage per transport type (udp/tcp).
    pub fn get_bytes_by_transport_type(&self, tt: TransportType) -> u64 {
        self.get_bytes_by_filter(None, None, Some(tt))
    }

    /// Get network usage per inout type (udp/tcp).
    pub fn get_bytes_by_inout_type(&self, i: InoutType) -> u64 {
        self.get_bytes_by_filter(None, Some(i), None)
    }

    /// List all pids which have some data attached.
    pub fn get_all_pids(&self) -> Vec<Pid> {
        let mut pids: Vec<_> = self.map.keys().map(|&(pid_opt, _, _)| pid_opt)
                                                .filter_map(|pid_opt| pid_opt)
                                                .collect();
        pids.sort();
        pids.dedup();
        pids
    }

    /// None as pid means "traffic that could not be assinged to pid".
    /// None for inout_type or transport_type means "can be anything"
    pub fn get_bytes_by_attr(&self, pid: Option<Pid>, inout_type: Option<InoutType>, transport_type: Option<TransportType>) -> u64 {
        let mut b = 0;
        for &io_attr in [None, Some(InoutType::Incoming), Some(InoutType::Outgoing)].into_iter() {
            if inout_type != None && inout_type != io_attr { continue }
            for &tt_attr in [None, Some(TransportType::Tcp), Some(TransportType::Udp)].into_iter() {
                if transport_type != None && transport_type != tt_attr { continue }

                b += self.map.get(&(pid, io_attr, tt_attr)).map(|&x| x).unwrap_or(0);
            }
        }

        b
    }

    /// Total number of bytes that couldn't be assigned to pid.
    pub fn get_unassigned_bytes(&self) -> u64 {
        self.get_bytes_by_attr(None, None, None)
    }

    /// Total number of bytes that can be assigned to a pid.
    pub fn get_assigned_bytes(&self) -> u64 {
        self.map.iter().filter(|&(&(pid_opt, _, _), _)| pid_opt.is_some()).fold(0, |acc, (_, bytes)| acc + bytes)
    }

    /// Total number of bytes.
    /// Some packets might dropped if they can't be handled fast enough. So this "total" value
    /// (and every other value) might not be the real value if CPU is working to capacity.
    ///
    /// Please use the information from the kernel for that purpose.
    pub fn get_total(&self) -> u64 {
        self.map.values().fold(0, |acc, bytes| acc + bytes)
    }
}

/// This structure allows you to group network traffic by pid.
#[allow(missing_debug_implementations)] // TODO
pub struct Netinfo {
    capture_handle: Arc<Mutex<CaptureHandle>>,

    /// This will be updated by the closure which is given to PacketCapture.
    statistics: Arc<Mutex<NetStatistics>>,

    /// will be set by `start*()` and `stop()`
    stop_request: Arc<Mutex<StopRequest>>,

    /// will be set by `start_async()` and `stop()`
    thread_error: Arc<Mutex<Option<Error>>>,

    thread_handle_opt: Option<JoinHandle<()>>,
}

impl Netinfo {
    /// Lists all non-loopback, active (= up and runnig) network interfaces
    pub fn list_net_interfaces() -> Result<Vec<NetworkInterface>> {
        Ok(CaptureHandle::list_net_interfaces().into_iter().map(|i| NetworkInterface::from(i)).collect())
    }

    /// Constructor for Netinfo. WARNING: this function will only handle the first NetworkInterface -
    /// tracking multiple interfaces at the same time will be implemented in the future. Until then
    /// this signature is there for API stability.
    pub fn new(interfaces: &[NetworkInterface]) -> Result<Netinfo> {
        // These variables are shared between the Netinfo object and the closure in CaptureHandle.
        let packet_matcher = Arc::new(Mutex::new(PacketMatcher::new()));
        let statistics = Arc::new(Mutex::new(NetStatistics::default()));
        let stop_request = Arc::new(Mutex::new(StopRequest::Continue));
        let packet_handler_closure = {
            // copy required fields
            let mut statistics = statistics.clone();
            let mut packet_matcher = packet_matcher.clone();
            let stop_request = stop_request.clone();

            // The closure which redirects packet to Self::handle_packet().
            // This closure will be called every time a packet is captured by CaptureHandle.
            move |packet_info: PacketInfo| -> Result<StopRequest> {
                Self::handle_packet(&mut packet_matcher, &mut statistics, packet_info)?;
                Ok(*stop_request.lock().unwrap())
            }
        };

        // convert from newtype to original type that libpnet can use
        let pnet_interfaces: Vec<PnetNetworkInterface> = interfaces.iter().map(|i| PnetNetworkInterface::from(i.clone())).collect();

        Ok(Netinfo {
            capture_handle:
                Arc::new(Mutex::new(CaptureHandle::new(&pnet_interfaces[0],
                                                       packet_handler_closure)?)),
            stop_request: stop_request,
            thread_error: Arc::new(Mutex::new(None)),
            statistics: statistics,
            thread_handle_opt: None,
        })
    }

    fn handle_packet(packet_matcher: &mut Arc<Mutex<PacketMatcher>>,
                     statistics: &mut Arc<Mutex<NetStatistics>>,
                     packet_info: PacketInfo) -> Result<()> {
        let pid_opt = {
            packet_matcher.lock().unwrap().find_pid(packet_info.clone())?
        };
        statistics.lock().unwrap().add_bytes(pid_opt, packet_info.inout_type, Some(packet_info.transport_type), packet_info.datalen);
        Ok(())
    }

    /// Returns the statistics about traffic since last clear.
    pub fn get_net_statistics(&self) -> Result<NetStatistics> {
        Ok(self.statistics.lock().unwrap().clone())
    }

    /// Resets the statistics.
    pub fn clear(&mut self) -> Result<()> {
        *self.statistics.lock().unwrap() = NetStatistics::default();
        Ok(())
    }

    /// Start capture in current thread. This function will block until an error occurs (may take a LOOOONG time). The error is then output with the
    /// return.
    pub fn start(&mut self) -> Result<()> {
        *self.stop_request.lock().unwrap() = StopRequest::Continue;
        self.capture_handle.lock().unwrap().handle_packets()
    }

    /// Stop capture in whether it was started by `start()` or `start*()` (function may be called from a different thread). Note that `start()` will
    /// not immediately unblock and the worker thread created by `start_async()` is not immediately ended - instead they will both stop on the next
    /// packet capture (this is due to a limitation in the packet capture library - as soon as it has non-blocking packet capturing this can be resolved).
    pub fn stop(&mut self) -> Result<()> {
        *self.stop_request.lock().unwrap() = StopRequest::Stop;
        Ok(())
    }

    /// Return the possible errors of the worker thread started by `start_async()`. Since there is no notification when errors occur (e.g. `get_net_statistics()` still resturns `Ok(())`), please check on this
    /// value regularly and before restarting a a new worker thread (check for `Ok(Some(some_error))`). A returned error means that the worker thread stopped.
    ///
    /// By calling this function, the error is cleared (so a subsequent call will return `None` if no other error occured in a new thread).
    ///
    /// The `Result` is there for general error handling, the enclosed `Option<Error>` is the actual return value.
    pub fn pop_thread_error(&mut self) -> Result<Option<Error>> {
        Ok(self.thread_error.lock().unwrap().take())
    }

    /// Start capture in different thread. This function will not block.
    ///
    /// Note: Starting a new thread while the old thread prior a `stop()` or `pop_thread_error()` with `Some(error)` results in
    /// undefined behavior.
    pub fn start_async(&mut self) -> Result<()> {
        *self.stop_request.lock().unwrap() = StopRequest::Continue;

        let capture_handle = self.capture_handle.clone();
        let thread_error = self.thread_error.clone();
        self.thread_handle_opt = Some(thread::spawn(move || {
            let result: Result<()> = capture_handle.lock().unwrap().handle_packets();

            // write errors but do not replace an `error` with `no error`
            if let Err(e) = result {
                *thread_error.lock().unwrap() = Some(e);
            }
        }));

        Ok(())
    }
}
<commit_msg>Use Shared<T> for Arc<Mutex<T>><commit_after>use netinfo::{Pid, PacketInfo, CaptureHandle, PacketMatcher, InoutType, TransportType, NetworkInterface, StopRequest};
use pnet::datalink::NetworkInterface as PnetNetworkInterface;
use std::sync::Arc;
use std::sync::Mutex;
use std::collections::HashMap;
use std::thread;
use std::thread::{JoinHandle};
use netinfo::error::*;

#[derive(Clone, Debug, Default)]
/// Contains detailed information on network usage on per attribute (pid, in/out, tcp/udp).
pub struct NetStatistics {
    /// Usage per "Pid | Inout | Udp/Tcp". Some values might not be known (we know a package is tcp-outgoing but can't
    /// figure out an associated process).
    map: HashMap<(Option<Pid>, Option<InoutType>, Option<TransportType>), u64>,
}

impl NetStatistics {
    fn add_bytes(&mut self, pid: Option<Pid>, c: Option<InoutType>, tt: Option<TransportType>, b: u64) {
        *self.map.entry((pid, c, tt)).or_insert(0) += b;
    }

    /// None means "this value can be arbitrary".
    fn get_bytes_by_filter(&self, pid: Option<Pid>, c: Option<InoutType>, tt: Option<TransportType>) -> u64 {
        self.map.iter()
                .filter(|&(&(kpid, kc, ktt), _)| (pid == None || pid == kpid) && (c == None || c == kc) && (tt == None || tt == ktt))
                .map(|(_, &b)| b)
                .fold(0, |b, acc| b + acc)
    }

    /// Get network usage per pid.
    pub fn get_bytes_by_pid(&self, pid: Pid) -> u64 {
        self.get_bytes_by_attr(Some(pid), None, None)
    }

    /// Get network usage per transport type (udp/tcp).
    pub fn get_bytes_by_transport_type(&self, tt: TransportType) -> u64 {
        self.get_bytes_by_filter(None, None, Some(tt))
    }

    /// Get network usage per inout type (udp/tcp).
    pub fn get_bytes_by_inout_type(&self, i: InoutType) -> u64 {
        self.get_bytes_by_filter(None, Some(i), None)
    }

    /// List all pids which have some data attached.
    pub fn get_all_pids(&self) -> Vec<Pid> {
        let mut pids: Vec<_> = self.map.keys().map(|&(pid_opt, _, _)| pid_opt)
                                                .filter_map(|pid_opt| pid_opt)
                                                .collect();
        pids.sort();
        pids.dedup();
        pids
    }

    /// None as pid means "traffic that could not be assinged to pid".
    /// None for inout_type or transport_type means "can be anything"
    pub fn get_bytes_by_attr(&self, pid: Option<Pid>, inout_type: Option<InoutType>, transport_type: Option<TransportType>) -> u64 {
        let mut b = 0;
        for &io_attr in [None, Some(InoutType::Incoming), Some(InoutType::Outgoing)].into_iter() {
            if inout_type != None && inout_type != io_attr { continue }
            for &tt_attr in [None, Some(TransportType::Tcp), Some(TransportType::Udp)].into_iter() {
                if transport_type != None && transport_type != tt_attr { continue }

                b += self.map.get(&(pid, io_attr, tt_attr)).map(|&x| x).unwrap_or(0);
            }
        }

        b
    }

    /// Total number of bytes that couldn't be assigned to pid.
    pub fn get_unassigned_bytes(&self) -> u64 {
        self.get_bytes_by_attr(None, None, None)
    }

    /// Total number of bytes that can be assigned to a pid.
    pub fn get_assigned_bytes(&self) -> u64 {
        self.map.iter().filter(|&(&(pid_opt, _, _), _)| pid_opt.is_some()).fold(0, |acc, (_, bytes)| acc + bytes)
    }

    /// Total number of bytes.
    /// Some packets might dropped if they can't be handled fast enough. So this "total" value
    /// (and every other value) might not be the real value if CPU is working to capacity.
    ///
    /// Please use the information from the kernel for that purpose.
    pub fn get_total(&self) -> u64 {
        self.map.values().fold(0, |acc, bytes| acc + bytes)
    }
}

// this makes the multi-threaded types more readable
type Shared<T> = Arc<Mutex<T>>;
fn new_shared<T>(t: T) -> Shared<T> { Arc::new(Mutex::new(t)) }

/// This structure allows you to group network traffic by pid.
#[allow(missing_debug_implementations)] // TODO
pub struct Netinfo {
    capture_handle: Shared<CaptureHandle>,

    /// This will be updated by the closure which is given to PacketCapture.
    statistics: Shared<NetStatistics>,

    /// will be set by `start*()` and `stop()`
    stop_request: Shared<StopRequest>,

    /// will be set by `start_async()` and `stop()`
    thread_error: Shared<Option<Error>>,

    thread_handle_opt: Option<JoinHandle<()>>,
}

impl Netinfo {
    /// Lists all non-loopback, active (= up and runnig) network interfaces
    pub fn list_net_interfaces() -> Result<Vec<NetworkInterface>> {
        Ok(CaptureHandle::list_net_interfaces().into_iter().map(|i| NetworkInterface::from(i)).collect())
    }

    /// Constructor for Netinfo. WARNING: this function will only handle the first NetworkInterface -
    /// tracking multiple interfaces at the same time will be implemented in the future. Until then
    /// this signature is there for API stability.
    pub fn new(interfaces: &[NetworkInterface]) -> Result<Netinfo> {
        // These variables are shared between the Netinfo object and the closure in CaptureHandle.
        let packet_matcher = new_shared(PacketMatcher::new());
        let statistics = new_shared(NetStatistics::default());
        let stop_request = new_shared(StopRequest::Continue);
        let packet_handler_closure = {
            // copy required fields
            let mut statistics = statistics.clone();
            let mut packet_matcher = packet_matcher.clone();
            let stop_request = stop_request.clone();

            // The closure which redirects packet to Self::handle_packet().
            // This closure will be called every time a packet is captured by CaptureHandle.
            move |packet_info: PacketInfo| -> Result<StopRequest> {
                Self::handle_packet(&mut packet_matcher, &mut statistics, packet_info)?;
                Ok(*stop_request.lock().unwrap())
            }
        };

        // convert from newtype to original type that libpnet can use
        let pnet_interfaces: Vec<PnetNetworkInterface> = interfaces.iter().map(|i| PnetNetworkInterface::from(i.clone())).collect();

        Ok(Netinfo {
            capture_handle:
                Arc::new(Mutex::new(CaptureHandle::new(&pnet_interfaces[0],
                                                       packet_handler_closure)?)),
            stop_request: stop_request,
            thread_error: Arc::new(Mutex::new(None)),
            statistics: statistics,
            thread_handle_opt: None,
        })
    }

    fn handle_packet(packet_matcher: &mut Shared<PacketMatcher>,
                     statistics: &mut Shared<NetStatistics>,
                     packet_info: PacketInfo) -> Result<()> {
        let pid_opt = {
            packet_matcher.lock().unwrap().find_pid(packet_info.clone())?
        };
        statistics.lock().unwrap().add_bytes(pid_opt, packet_info.inout_type, Some(packet_info.transport_type), packet_info.datalen);
        Ok(())
    }

    /// Returns the statistics about traffic since last clear.
    pub fn get_net_statistics(&self) -> Result<NetStatistics> {
        Ok(self.statistics.lock().unwrap().clone())
    }

    /// Resets the statistics.
    pub fn clear(&mut self) -> Result<()> {
        *self.statistics.lock().unwrap() = NetStatistics::default();
        Ok(())
    }

    /// Start capture in current thread. This function will block until an error occurs (may take a LOOOONG time). The error is then output with the
    /// return.
    pub fn start(&mut self) -> Result<()> {
        *self.stop_request.lock().unwrap() = StopRequest::Continue;
        self.capture_handle.lock().unwrap().handle_packets()
    }

    /// Stop capture in whether it was started by `start()` or `start*()` (function may be called from a different thread). Note that `start()` will
    /// not immediately unblock and the worker thread created by `start_async()` is not immediately ended - instead they will both stop on the next
    /// packet capture (this is due to a limitation in the packet capture library - as soon as it has non-blocking packet capturing this can be resolved).
    pub fn stop(&mut self) -> Result<()> {
        *self.stop_request.lock().unwrap() = StopRequest::Stop;
        Ok(())
    }

    /// Return the possible errors of the worker thread started by `start_async()`. Since there is no notification when errors occur (e.g. `get_net_statistics()` still resturns `Ok(())`), please check on this
    /// value regularly and before restarting a a new worker thread (check for `Ok(Some(some_error))`). A returned error means that the worker thread stopped.
    ///
    /// By calling this function, the error is cleared (so a subsequent call will return `None` if no other error occured in a new thread).
    ///
    /// The `Result` is there for general error handling, the enclosed `Option<Error>` is the actual return value.
    pub fn pop_thread_error(&mut self) -> Result<Option<Error>> {
        Ok(self.thread_error.lock().unwrap().take())
    }

    /// Start capture in different thread. This function will not block.
    ///
    /// Note: Starting a new thread while the old thread prior a `stop()` or `pop_thread_error()` with `Some(error)` results in
    /// undefined behavior.
    pub fn start_async(&mut self) -> Result<()> {
        *self.stop_request.lock().unwrap() = StopRequest::Continue;

        let capture_handle = self.capture_handle.clone();
        let thread_error = self.thread_error.clone();
        self.thread_handle_opt = Some(thread::spawn(move || {
            let result: Result<()> = capture_handle.lock().unwrap().handle_packets();

            // write errors but do not replace an `error` with `no error`
            if let Err(e) = result {
                *thread_error.lock().unwrap() = Some(e);
            }
        }));

        Ok(())
    }
}
<|endoftext|>


<commit_before>mod advent_of_code;

use std::cmp::{max,min};
use std::io;
use std::io::BufRead;

// assume square
const KEYPAD_SIZE: i32 = 3;

#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
struct KeyPadPosition
{
    row: i32,
    column: i32,
}

impl KeyPadPosition
{
    fn bounded(number: i32)
        -> i32
    {
        return max(0, min(number, KEYPAD_SIZE - 1));
    }

    fn get_key(&self)
        -> char
    {
        // TODO: can this be global static?
        let pad: [[char; 3]; 3] = [
            ['1', '2', '3'],
            ['4', '5', '6'],
            ['7', '8', '9'],
        ];
        return pad[self.row as usize][self.column as usize];
    }

    fn moved_up(&self)
        -> KeyPadPosition
    {
        return KeyPadPosition {
            row: Self::bounded(self.row - 1),
            column: self.column,
        };
    }

    fn moved_down(&self)
        -> KeyPadPosition
    {
        return KeyPadPosition {
            row: Self::bounded(self.row + 1),
            column: self.column,
        };
    }

    fn moved_right(&self)
        -> KeyPadPosition
    {
        return KeyPadPosition {
            row: self.row,
            column: Self::bounded(self.column + 1),
        };
    }

    fn moved_left(&self)
        -> KeyPadPosition
    {
        return KeyPadPosition {
            row: self.row,
            column: Self::bounded(self.column - 1),
        };
    }
}

#[cfg(test)]
mod test
{
    use KeyPadPosition;
    use KEYPAD_SIZE;

    #[test]
    fn test_bounded_up_from_first_row()
    {
        let expected = KeyPadPosition { row: 0, column: 1 };
        let actual = expected.moved_up();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_left_from_first_column()
    {
        let expected = KeyPadPosition { row: 1, column: 0 };
        let actual = expected.moved_left();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_down_from_last_row()
    {
        let expected = KeyPadPosition { row: KEYPAD_SIZE - 1, column: 1 };
        let actual = expected.moved_down();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_right_from_last_col()
    {
        let expected = KeyPadPosition { row: 1, column: KEYPAD_SIZE - 1 };
        let actual = expected.moved_right();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_up_from_middle()
    {
        let pos = KeyPadPosition { row: 1, column: 1 };
        let expected = KeyPadPosition { row: 0, column: 1 };
        let actual = pos.moved_up();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_left_from_middle()
    {
        let pos = KeyPadPosition { row: 1, column: 1 };
        let expected = KeyPadPosition { row: 1, column: 0 };
        let actual = pos.moved_left();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_down_from_middle()
    {
        let pos = KeyPadPosition { row: 1, column: 1 };
        let expected = KeyPadPosition { row: 2, column: 1 };
        let actual = pos.moved_down();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_right_from_middle()
    {
        let pos = KeyPadPosition { row: 1, column: 1 };
        let expected = KeyPadPosition { row: 1, column: 2 };
        let actual = pos.moved_right();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_get_key_1()
    {
        let pos = KeyPadPosition { row: 0, column: 0 };
        let actual = pos.get_key();
        assert_eq!(actual, '1');
    }

    #[test]
    fn test_get_key_3()
    {
        let pos = KeyPadPosition { row: 0, column: 2 };
        let actual = pos.get_key();
        assert_eq!(actual, '3');
    }

    #[test]
    fn test_get_key_4()
    {
        let pos = KeyPadPosition { row: 1, column: 0 };
        let actual = pos.get_key();
        assert_eq!(actual, '4');
    }
}

#[cfg(not(test))]
fn main()
{
    let stdin = io::stdin();
    let mut pad_position = KeyPadPosition { row: 1, column: 1 };

    for line in stdin.lock().lines()
    {
        for chr in line.unwrap().chars()
        {
            if chr == 'U'
            {
                pad_position = pad_position.moved_up();
            }
            else if chr == 'D'
            {
                pad_position = pad_position.moved_down();
            }
            else if chr == 'R'
            {
                pad_position = pad_position.moved_right();
            }
            else if chr == 'L'
            {
                pad_position = pad_position.moved_left();
            }
            else
            {
                panic!("Unexpected character '{:?}'.", chr);
            }
        }
        let key = pad_position.get_key();
        print!("{}", key);
    }
    println!("");
}
<commit_msg>Make it possible to have invalid positions<commit_after>mod advent_of_code;

use std::cmp::{max,min};
use std::io;
use std::io::BufRead;

// assume square
const KEYPAD_SIZE: i32 = 3;

#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
struct KeyPadPosition
{
    row: i32,
    column: i32,
}

impl KeyPadPosition
{
    fn bounded(number: i32)
        -> i32
    {
        return max(0, min(number, KEYPAD_SIZE - 1));
    }

    fn get_key(&self)
        -> Option<char>
    {
        if self.row < 0 || self.row >= KEYPAD_SIZE ||
        self.column < 0 || self.column >= KEYPAD_SIZE
        {
            return None;
        }

        // TODO: can this be global static?
        let pad: [[Option<char>; 3]; 3] = [
            [Some('1'), Some('2'), Some('3')],
            [Some('4'), Some('5'), Some('6')],
            [Some('7'), Some('8'), Some('9')],
        ];
        return pad[self.row as usize][self.column as usize];
    }

    fn is_valid(&self)
        -> bool
    {
        return match self.get_key() {
            Some(_) => true,
            None => false,
        }
    }

    fn or_if_valid(&self, pos: KeyPadPosition)
        -> KeyPadPosition
    {
        if pos.is_valid()
        {
            return pos;
        }
        return *self;
    }

    fn moved_up(&self)
        -> KeyPadPosition
    {
        return self.or_if_valid(KeyPadPosition {
            row: Self::bounded(self.row - 1),
            column: self.column,
        });
    }

    fn moved_down(&self)
        -> KeyPadPosition
    {
        return self.or_if_valid(KeyPadPosition {
            row: Self::bounded(self.row + 1),
            column: self.column,
        });
    }

    fn moved_right(&self)
        -> KeyPadPosition
    {
        return self.or_if_valid(KeyPadPosition {
            row: self.row,
            column: Self::bounded(self.column + 1),
        });
    }

    fn moved_left(&self)
        -> KeyPadPosition
    {
        return self.or_if_valid(KeyPadPosition {
            row: self.row,
            column: Self::bounded(self.column - 1),
        });
    }
}

#[cfg(test)]
mod test
{
    use KeyPadPosition;
    use KEYPAD_SIZE;

    #[test]
    fn test_bounded_up_from_first_row()
    {
        let expected = KeyPadPosition { row: 0, column: 1 };
        let actual = expected.moved_up();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_left_from_first_column()
    {
        let expected = KeyPadPosition { row: 1, column: 0 };
        let actual = expected.moved_left();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_down_from_last_row()
    {
        let expected = KeyPadPosition { row: KEYPAD_SIZE - 1, column: 1 };
        let actual = expected.moved_down();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_right_from_last_col()
    {
        let expected = KeyPadPosition { row: 1, column: KEYPAD_SIZE - 1 };
        let actual = expected.moved_right();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_up_from_middle()
    {
        let pos = KeyPadPosition { row: 1, column: 1 };
        let expected = KeyPadPosition { row: 0, column: 1 };
        let actual = pos.moved_up();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_left_from_middle()
    {
        let pos = KeyPadPosition { row: 1, column: 1 };
        let expected = KeyPadPosition { row: 1, column: 0 };
        let actual = pos.moved_left();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_down_from_middle()
    {
        let pos = KeyPadPosition { row: 1, column: 1 };
        let expected = KeyPadPosition { row: 2, column: 1 };
        let actual = pos.moved_down();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_bounded_right_from_middle()
    {
        let pos = KeyPadPosition { row: 1, column: 1 };
        let expected = KeyPadPosition { row: 1, column: 2 };
        let actual = pos.moved_right();
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_get_key_invalid()
    {
        let pos = KeyPadPosition { row: -1, column: 0 };
        let actual = pos.get_key();
        assert_eq!(actual, None);
    }

    #[test]
    fn test_get_key_1()
    {
        let pos = KeyPadPosition { row: 0, column: 0 };
        let actual = pos.get_key();
        assert_eq!(actual, Some('1'));
    }

    #[test]
    fn test_get_key_3()
    {
        let pos = KeyPadPosition { row: 0, column: 2 };
        let actual = pos.get_key();
        assert_eq!(actual, Some('3'));
    }

    #[test]
    fn test_get_key_4()
    {
        let pos = KeyPadPosition { row: 1, column: 0 };
        let actual = pos.get_key();
        assert_eq!(actual, Some('4'));
    }
}

#[cfg(not(test))]
fn main()
{
    let stdin = io::stdin();
    let mut pad_position = KeyPadPosition { row: 1, column: 1 };

    for line in stdin.lock().lines()
    {
        for chr in line.unwrap().chars()
        {
            if chr == 'U'
            {
                pad_position = pad_position.moved_up();
            }
            else if chr == 'D'
            {
                pad_position = pad_position.moved_down();
            }
            else if chr == 'R'
            {
                pad_position = pad_position.moved_right();
            }
            else if chr == 'L'
            {
                pad_position = pad_position.moved_left();
            }
            else
            {
                panic!("Unexpected character '{:?}'.", chr);
            }
        }
        let key = pad_position.get_key();
        match key {
            Some(k) => print!("{}", k),
            None => panic!("Managed to create an invalid position: {:?}.", pad_position),
        }
    }
    println!("");
}
<|endoftext|>