<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 back::link::exported_name;
use session;
use llvm::ValueRef;
use llvm;
use middle::infer;
use middle::subst;
use middle::subst::{Subst, Substs};
use middle::traits;
use middle::ty_fold::{TypeFolder, TypeFoldable};
use trans::base::{set_llvm_fn_attrs, set_inline_hint};
use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
use trans::base::{trans_fn, decl_internal_rust_fn};
use trans::base;
use trans::common::*;
use trans::foreign;
use middle::ty::{self, HasProjectionTypes, Ty};
use util::ppaux::Repr;

use syntax::abi;
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util::{local_def, PostExpansionMethod};
use syntax::attr;
use syntax::codemap::DUMMY_SP;
use std::hash::{sip, Hash};

pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                fn_id: ast::DefId,
                                psubsts: &subst::Substs<'tcx>,
                                ref_id: Option<ast::NodeId>)
    -> (ValueRef, Ty<'tcx>, bool) {
    debug!("monomorphic_fn(\
            fn_id={}, \
            real_substs={}, \
            ref_id={:?})",
           fn_id.repr(ccx.tcx()),
           psubsts.repr(ccx.tcx()),
           ref_id);

    assert!(psubsts.types.all(|t| {
        !ty::type_needs_infer(*t) && !ty::type_has_params(*t)
    }));

    let _icx = push_ctxt("monomorphic_fn");

    let hash_id = MonoId {
        def: fn_id,
        params: psubsts.types.clone()
    };

    let item_ty = ty::lookup_item_type(ccx.tcx(), fn_id).ty;
    let mono_ty = item_ty.subst(ccx.tcx(), psubsts);

    match ccx.monomorphized().borrow().get(&hash_id) {
        Some(&val) => {
            debug!("leaving monomorphic fn {}",
            ty::item_path_str(ccx.tcx(), fn_id));
            return (val, mono_ty, false);
        }
        None => ()
    }

    debug!("monomorphic_fn(\
            fn_id={}, \
            psubsts={}, \
            hash_id={:?})",
           fn_id.repr(ccx.tcx()),
           psubsts.repr(ccx.tcx()),
           hash_id);

    let map_node = session::expect(
        ccx.sess(),
        ccx.tcx().map.find(fn_id.node),
        || {
            format!("while monomorphizing {:?}, couldn't find it in \
                     the item map (may have attempted to monomorphize \
                     an item defined in a different crate?)",
                    fn_id)
        });

    if let ast_map::NodeForeignItem(_) = map_node {
        if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic {
            // Foreign externs don't have to be monomorphized.
            return (get_item_val(ccx, fn_id.node), mono_ty, true);
        }
    }

    debug!("monomorphic_fn about to subst into {}", item_ty.repr(ccx.tcx()));

    debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx()));

    let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
    debug!("mono_ty = {} (post-normalization)", mono_ty.repr(ccx.tcx()));

    ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);

    let depth;
    {
        let mut monomorphizing = ccx.monomorphizing().borrow_mut();
        depth = match monomorphizing.get(&fn_id) {
            Some(&d) => d, None => 0
        };

        // Random cut-off -- code that needs to instantiate the same function
        // recursively more than thirty times can probably safely be assumed
        // to be causing an infinite expansion.
        if depth > ccx.sess().recursion_limit.get() {
            ccx.sess().span_fatal(ccx.tcx().map.span(fn_id.node),
                "reached the recursion limit during monomorphization");
        }

        monomorphizing.insert(fn_id, depth + 1);
    }

    let hash;
    let s = {
        let mut state = sip::SipState::new();
        hash_id.hash(&mut state);
        mono_ty.hash(&mut state);

        hash = format!("h{}", state.result());
        ccx.tcx().map.with_path(fn_id.node, |path| {
            exported_name(path, hash.index(&FullRange))
        })
    };

    debug!("monomorphize_fn mangled to {}", s);

    // This shouldn't need to option dance.
    let mut hash_id = Some(hash_id);
    let mut mk_lldecl = |&mut : abi: abi::Abi| {
        let lldecl = if abi != abi::Rust {
            foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, s.index(&FullRange))
        } else {
            decl_internal_rust_fn(ccx, mono_ty, s.index(&FullRange))
        };

        ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl);
        lldecl
    };
    let setup_lldecl = |&: lldecl, attrs: &[ast::Attribute]| {
        base::update_linkage(ccx, lldecl, None, base::OriginalTranslation);
        set_llvm_fn_attrs(ccx, attrs, lldecl);

        let is_first = !ccx.available_monomorphizations().borrow().contains(&s);
        if is_first {
            ccx.available_monomorphizations().borrow_mut().insert(s.clone());
        }

        let trans_everywhere = attr::requests_inline(attrs);
        if trans_everywhere && !is_first {
            llvm::SetLinkage(lldecl, llvm::AvailableExternallyLinkage);
        }

        // If `true`, then `lldecl` should be given a function body.
        // Otherwise, it should be left as a declaration of an external
        // function, with no definition in the current compilation unit.
        trans_everywhere || is_first
    };

    let lldecl = match map_node {
        ast_map::NodeItem(i) => {
            match *i {
              ast::Item {
                  node: ast::ItemFn(ref decl, _, abi, _, ref body),
                  ..
              } => {
                  let d = mk_lldecl(abi);
                  let needs_body = setup_lldecl(d, i.attrs.index(&FullRange));
                  if needs_body {
                      if abi != abi::Rust {
                          foreign::trans_rust_fn_with_foreign_abi(
                              ccx, &**decl, &**body, &[], d, psubsts, fn_id.node,
                              Some(hash.index(&FullRange)));
                      } else {
                          trans_fn(ccx, &**decl, &**body, d, psubsts, fn_id.node, &[]);
                      }
                  }

                  d
              }
              _ => {
                ccx.sess().bug("Can't monomorphize this kind of item")
              }
            }
        }
        ast_map::NodeVariant(v) => {
            let parent = ccx.tcx().map.get_parent(fn_id.node);
            let tvs = ty::enum_variants(ccx.tcx(), local_def(parent));
            let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap();
            let d = mk_lldecl(abi::Rust);
            set_inline_hint(d);
            match v.node.kind {
                ast::TupleVariantKind(ref args) => {
                    trans_enum_variant(ccx,
                                       parent,
                                       &*v,
                                       args.index(&FullRange),
                                       this_tv.disr_val,
                                       psubsts,
                                       d);
                }
                ast::StructVariantKind(_) =>
                    ccx.sess().bug("can't monomorphize struct variants"),
            }
            d
        }
        ast_map::NodeImplItem(ii) => {
            match *ii {
                ast::MethodImplItem(ref mth) => {
                    let d = mk_lldecl(abi::Rust);
                    let needs_body = setup_lldecl(d, mth.attrs.index(&FullRange));
                    if needs_body {
                        trans_fn(ccx,
                                 mth.pe_fn_decl(),
                                 mth.pe_body(),
                                 d,
                                 psubsts,
                                 mth.id,
                                 &[]);
                    }
                    d
                }
                ast::TypeImplItem(_) => {
                    ccx.sess().bug("can't monomorphize an associated type")
                }
            }
        }
        ast_map::NodeTraitItem(method) => {
            match *method {
                ast::ProvidedMethod(ref mth) => {
                    let d = mk_lldecl(abi::Rust);
                    let needs_body = setup_lldecl(d, mth.attrs.index(&FullRange));
                    if needs_body {
                        trans_fn(ccx, mth.pe_fn_decl(), mth.pe_body(), d,
                                 psubsts, mth.id, &[]);
                    }
                    d
                }
                _ => {
                    ccx.sess().bug(format!("can't monomorphize a {:?}",
                                           map_node).index(&FullRange))
                }
            }
        }
        ast_map::NodeStructCtor(struct_def) => {
            let d = mk_lldecl(abi::Rust);
            set_inline_hint(d);
            base::trans_tuple_struct(ccx,
                                     struct_def.fields.index(&FullRange),
                                     struct_def.ctor_id.expect("ast-mapped tuple struct \
                                                                didn't have a ctor id"),
                                     psubsts,
                                     d);
            d
        }

        // Ugh -- but this ensures any new variants won't be forgotten
        ast_map::NodeForeignItem(..) |
        ast_map::NodeLifetime(..) |
        ast_map::NodeExpr(..) |
        ast_map::NodeStmt(..) |
        ast_map::NodeArg(..) |
        ast_map::NodeBlock(..) |
        ast_map::NodePat(..) |
        ast_map::NodeLocal(..) => {
            ccx.sess().bug(format!("can't monomorphize a {:?}",
                                   map_node).index(&FullRange))
        }
    };

    ccx.monomorphizing().borrow_mut().insert(fn_id, depth);

    debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id));
    (lldecl, mono_ty, true)
}

#[derive(PartialEq, Eq, Hash, Show)]
pub struct MonoId<'tcx> {
    pub def: ast::DefId,
    pub params: subst::VecPerParamSpace<Ty<'tcx>>
}

/// Monomorphizes a type from the AST by first applying the in-scope
/// substitutions and then normalizing any associated types.
pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
                                  param_substs: &Substs<'tcx>,
                                  value: &T)
                                  -> T
    where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
{
    assert!(param_substs.regions.is_erased());

    let substituted = value.subst(tcx, param_substs);
    normalize_associated_type(tcx, &substituted)
}

/// Removes associated types, if any. Since this during
/// monomorphization, we know that only concrete types are involved,
/// and hence we can be sure that all associated types will be
/// completely normalized away.
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
    where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
{
    debug!("normalize_associated_type(t={})", value.repr(tcx));

    if !value.has_projection_types() {
        return value.clone();
    }

    // FIXME(#20304) -- cache

    let infcx = infer::new_infer_ctxt(tcx);
    let typer = NormalizingUnboxedClosureTyper::new(tcx);
    let mut selcx = traits::SelectionContext::new(&infcx, &typer);
    let cause = traits::ObligationCause::dummy();
    let traits::Normalized { value: result, obligations } =
        traits::normalize(&mut selcx, cause, value);

    debug!("normalize_associated_type: result={} obligations={}",
           result.repr(tcx),
           obligations.repr(tcx));

    let mut fulfill_cx = traits::FulfillmentContext::new();
    for obligation in obligations.into_iter() {
        fulfill_cx.register_predicate_obligation(&infcx, obligation);
    }
    let result = drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &result);

    result
}
<commit_msg>Remove assertion that substitutions are erased. It'd be nice if they always were but it's dang annoying to weed out all the places that fail to meet the assertion, and it doesn't really hurt things if we don't always get it right.<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 back::link::exported_name;
use session;
use llvm::ValueRef;
use llvm;
use middle::infer;
use middle::subst;
use middle::subst::{Subst, Substs};
use middle::traits;
use middle::ty_fold::{TypeFolder, TypeFoldable};
use trans::base::{set_llvm_fn_attrs, set_inline_hint};
use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
use trans::base::{trans_fn, decl_internal_rust_fn};
use trans::base;
use trans::common::*;
use trans::foreign;
use middle::ty::{self, HasProjectionTypes, Ty};
use util::ppaux::Repr;

use syntax::abi;
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util::{local_def, PostExpansionMethod};
use syntax::attr;
use syntax::codemap::DUMMY_SP;
use std::hash::{sip, Hash};

pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                fn_id: ast::DefId,
                                psubsts: &subst::Substs<'tcx>,
                                ref_id: Option<ast::NodeId>)
    -> (ValueRef, Ty<'tcx>, bool) {
    debug!("monomorphic_fn(\
            fn_id={}, \
            real_substs={}, \
            ref_id={:?})",
           fn_id.repr(ccx.tcx()),
           psubsts.repr(ccx.tcx()),
           ref_id);

    assert!(psubsts.types.all(|t| {
        !ty::type_needs_infer(*t) && !ty::type_has_params(*t)
    }));

    let _icx = push_ctxt("monomorphic_fn");

    let hash_id = MonoId {
        def: fn_id,
        params: psubsts.types.clone()
    };

    let item_ty = ty::lookup_item_type(ccx.tcx(), fn_id).ty;
    let mono_ty = item_ty.subst(ccx.tcx(), psubsts);

    match ccx.monomorphized().borrow().get(&hash_id) {
        Some(&val) => {
            debug!("leaving monomorphic fn {}",
            ty::item_path_str(ccx.tcx(), fn_id));
            return (val, mono_ty, false);
        }
        None => ()
    }

    debug!("monomorphic_fn(\
            fn_id={}, \
            psubsts={}, \
            hash_id={:?})",
           fn_id.repr(ccx.tcx()),
           psubsts.repr(ccx.tcx()),
           hash_id);

    let map_node = session::expect(
        ccx.sess(),
        ccx.tcx().map.find(fn_id.node),
        || {
            format!("while monomorphizing {:?}, couldn't find it in \
                     the item map (may have attempted to monomorphize \
                     an item defined in a different crate?)",
                    fn_id)
        });

    if let ast_map::NodeForeignItem(_) = map_node {
        if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic {
            // Foreign externs don't have to be monomorphized.
            return (get_item_val(ccx, fn_id.node), mono_ty, true);
        }
    }

    debug!("monomorphic_fn about to subst into {}", item_ty.repr(ccx.tcx()));

    debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx()));

    let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
    debug!("mono_ty = {} (post-normalization)", mono_ty.repr(ccx.tcx()));

    ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);

    let depth;
    {
        let mut monomorphizing = ccx.monomorphizing().borrow_mut();
        depth = match monomorphizing.get(&fn_id) {
            Some(&d) => d, None => 0
        };

        // Random cut-off -- code that needs to instantiate the same function
        // recursively more than thirty times can probably safely be assumed
        // to be causing an infinite expansion.
        if depth > ccx.sess().recursion_limit.get() {
            ccx.sess().span_fatal(ccx.tcx().map.span(fn_id.node),
                "reached the recursion limit during monomorphization");
        }

        monomorphizing.insert(fn_id, depth + 1);
    }

    let hash;
    let s = {
        let mut state = sip::SipState::new();
        hash_id.hash(&mut state);
        mono_ty.hash(&mut state);

        hash = format!("h{}", state.result());
        ccx.tcx().map.with_path(fn_id.node, |path| {
            exported_name(path, hash.index(&FullRange))
        })
    };

    debug!("monomorphize_fn mangled to {}", s);

    // This shouldn't need to option dance.
    let mut hash_id = Some(hash_id);
    let mut mk_lldecl = |&mut : abi: abi::Abi| {
        let lldecl = if abi != abi::Rust {
            foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, s.index(&FullRange))
        } else {
            decl_internal_rust_fn(ccx, mono_ty, s.index(&FullRange))
        };

        ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl);
        lldecl
    };
    let setup_lldecl = |&: lldecl, attrs: &[ast::Attribute]| {
        base::update_linkage(ccx, lldecl, None, base::OriginalTranslation);
        set_llvm_fn_attrs(ccx, attrs, lldecl);

        let is_first = !ccx.available_monomorphizations().borrow().contains(&s);
        if is_first {
            ccx.available_monomorphizations().borrow_mut().insert(s.clone());
        }

        let trans_everywhere = attr::requests_inline(attrs);
        if trans_everywhere && !is_first {
            llvm::SetLinkage(lldecl, llvm::AvailableExternallyLinkage);
        }

        // If `true`, then `lldecl` should be given a function body.
        // Otherwise, it should be left as a declaration of an external
        // function, with no definition in the current compilation unit.
        trans_everywhere || is_first
    };

    let lldecl = match map_node {
        ast_map::NodeItem(i) => {
            match *i {
              ast::Item {
                  node: ast::ItemFn(ref decl, _, abi, _, ref body),
                  ..
              } => {
                  let d = mk_lldecl(abi);
                  let needs_body = setup_lldecl(d, i.attrs.index(&FullRange));
                  if needs_body {
                      if abi != abi::Rust {
                          foreign::trans_rust_fn_with_foreign_abi(
                              ccx, &**decl, &**body, &[], d, psubsts, fn_id.node,
                              Some(hash.index(&FullRange)));
                      } else {
                          trans_fn(ccx, &**decl, &**body, d, psubsts, fn_id.node, &[]);
                      }
                  }

                  d
              }
              _ => {
                ccx.sess().bug("Can't monomorphize this kind of item")
              }
            }
        }
        ast_map::NodeVariant(v) => {
            let parent = ccx.tcx().map.get_parent(fn_id.node);
            let tvs = ty::enum_variants(ccx.tcx(), local_def(parent));
            let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap();
            let d = mk_lldecl(abi::Rust);
            set_inline_hint(d);
            match v.node.kind {
                ast::TupleVariantKind(ref args) => {
                    trans_enum_variant(ccx,
                                       parent,
                                       &*v,
                                       args.index(&FullRange),
                                       this_tv.disr_val,
                                       psubsts,
                                       d);
                }
                ast::StructVariantKind(_) =>
                    ccx.sess().bug("can't monomorphize struct variants"),
            }
            d
        }
        ast_map::NodeImplItem(ii) => {
            match *ii {
                ast::MethodImplItem(ref mth) => {
                    let d = mk_lldecl(abi::Rust);
                    let needs_body = setup_lldecl(d, mth.attrs.index(&FullRange));
                    if needs_body {
                        trans_fn(ccx,
                                 mth.pe_fn_decl(),
                                 mth.pe_body(),
                                 d,
                                 psubsts,
                                 mth.id,
                                 &[]);
                    }
                    d
                }
                ast::TypeImplItem(_) => {
                    ccx.sess().bug("can't monomorphize an associated type")
                }
            }
        }
        ast_map::NodeTraitItem(method) => {
            match *method {
                ast::ProvidedMethod(ref mth) => {
                    let d = mk_lldecl(abi::Rust);
                    let needs_body = setup_lldecl(d, mth.attrs.index(&FullRange));
                    if needs_body {
                        trans_fn(ccx, mth.pe_fn_decl(), mth.pe_body(), d,
                                 psubsts, mth.id, &[]);
                    }
                    d
                }
                _ => {
                    ccx.sess().bug(format!("can't monomorphize a {:?}",
                                           map_node).index(&FullRange))
                }
            }
        }
        ast_map::NodeStructCtor(struct_def) => {
            let d = mk_lldecl(abi::Rust);
            set_inline_hint(d);
            base::trans_tuple_struct(ccx,
                                     struct_def.fields.index(&FullRange),
                                     struct_def.ctor_id.expect("ast-mapped tuple struct \
                                                                didn't have a ctor id"),
                                     psubsts,
                                     d);
            d
        }

        // Ugh -- but this ensures any new variants won't be forgotten
        ast_map::NodeForeignItem(..) |
        ast_map::NodeLifetime(..) |
        ast_map::NodeExpr(..) |
        ast_map::NodeStmt(..) |
        ast_map::NodeArg(..) |
        ast_map::NodeBlock(..) |
        ast_map::NodePat(..) |
        ast_map::NodeLocal(..) => {
            ccx.sess().bug(format!("can't monomorphize a {:?}",
                                   map_node).index(&FullRange))
        }
    };

    ccx.monomorphizing().borrow_mut().insert(fn_id, depth);

    debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id));
    (lldecl, mono_ty, true)
}

#[derive(PartialEq, Eq, Hash, Show)]
pub struct MonoId<'tcx> {
    pub def: ast::DefId,
    pub params: subst::VecPerParamSpace<Ty<'tcx>>
}

/// Monomorphizes a type from the AST by first applying the in-scope
/// substitutions and then normalizing any associated types.
pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
                                  param_substs: &Substs<'tcx>,
                                  value: &T)
                                  -> T
    where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
{
    let substituted = value.subst(tcx, param_substs);
    normalize_associated_type(tcx, &substituted)
}

/// Removes associated types, if any. Since this during
/// monomorphization, we know that only concrete types are involved,
/// and hence we can be sure that all associated types will be
/// completely normalized away.
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
    where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
{
    debug!("normalize_associated_type(t={})", value.repr(tcx));

    if !value.has_projection_types() {
        return value.clone();
    }

    // FIXME(#20304) -- cache

    let infcx = infer::new_infer_ctxt(tcx);
    let typer = NormalizingUnboxedClosureTyper::new(tcx);
    let mut selcx = traits::SelectionContext::new(&infcx, &typer);
    let cause = traits::ObligationCause::dummy();
    let traits::Normalized { value: result, obligations } =
        traits::normalize(&mut selcx, cause, value);

    debug!("normalize_associated_type: result={} obligations={}",
           result.repr(tcx),
           obligations.repr(tcx));

    let mut fulfill_cx = traits::FulfillmentContext::new();
    for obligation in obligations.into_iter() {
        fulfill_cx.register_predicate_obligation(&infcx, obligation);
    }
    let result = drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &result);

    result
}
<|endoftext|>


<commit_before>//! Commands from the user to manipulate the tree

use super::{try_lock_tree, try_lock_action};
use super::{Action, ActionErr, Container, ContainerType, Direction, Handle, Layout, TreeError};
use super::Tree;

use uuid::Uuid;
use rustwlc::{Geometry, Point, ResizeEdge, WlcView, WlcOutput, ViewType};

pub type CommandResult = Result<(), TreeError>;

/* These commands are exported to take nothing and return nothing,
 * since they are the commands actually registered and usable over
 * the IPC/Lua thread.
 */

pub fn remove_active() {
    if let Ok(mut tree) = try_lock_tree() {
        if let Some(container) = tree.0.get_active_container_mut() {
            match *container {
                Container::View { ref handle, .. } => {
                    handle.close();
                    // Thanks borrowck
                    // Views shouldn't be removed from tree, that's handled by
                    // view_destroyed callback
                    return
                },
                _ => {}
            }
        }
        tree.0.remove_active();
    }
}

pub fn toggle_float() {
    if let Ok(mut tree) = try_lock_tree() {
        if let Some(uuid) = tree.active_id() {
            let is_floating = tree.0.lookup(uuid)
                .and_then(|container| Ok(container.floating()));
            let err = match is_floating {
                Ok(true) => tree.ground_container(uuid),
                Ok(false) => tree.float_container(uuid),
                Err(err) => Err(err)
            };
            if let Err(err) = err {
                warn!("{:?},\nError while toggling the floating of {:#?}\n {:#?}", err, uuid, *tree.0);
            }
        }
    }
}

pub fn toggle_float_focus() {
    if let Ok(mut tree) = try_lock_tree() {
        if let Err(err) = tree.toggle_floating_focus() {
            warn!("Could not float focus: {:#?}", err);
        }
    }
}

pub fn tile_switch() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_cardinal_tiling();
        tree.layout_active_of(ContainerType::Workspace)
            .unwrap_or_else(|_| {
                warn!("Could not tile workspace");
            });
    }
}

pub fn split_vertical() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_active_layout(Layout::Vertical).ok();
    }
}

pub fn split_horizontal() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_active_layout(Layout::Horizontal).ok();
    }
}

pub fn focus_left() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Left)
            .unwrap_or_else(|_| {
                warn!("Could not focus left");
            });
    }
}

pub fn focus_right() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Right)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            });
    }
}

pub fn focus_up() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Up)
            .unwrap_or_else(|_| {
                warn!("Could not focus up");
            });
    }
}

pub fn focus_down() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Down)
            .unwrap_or_else(|_| {
                warn!("Could not focus down");
            });
    }
}

pub fn move_active_left() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Left)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

pub fn move_active_right() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Right)
            .unwrap_or_else(|_| {
                error!("Could not focus right");
            })
    }
}

pub fn move_active_up() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Up)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

pub fn move_active_down() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Down)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

/// Returns a copy of the action behind the lock.
pub fn performing_action() -> Option<Action> {
    if let Ok(action) = try_lock_action() {
        *action
    } else {
        error!("Could not lock action mutex!");
        None
    }
}

/// Sets the value behind the lock to the provided value.
///
/// Note that this method blocks until the lock is released
///
/// None means an action is done being performed.
pub fn set_performing_action(val: Option<Action>) {
    if let Ok(mut action) = try_lock_action() {
        *action = val;
    } else {
        error!("Action mutex was poisoned");
        panic!("Action mutex was poisoned");
    }
}

/* These commands are the interface that the rest of Way Cooler has to the
 * tree. Any action done, whether through a callback, or from the IPC/Lua thread
 * it will have to go through one of these methods.
 */

impl Tree {
    /// Gets the uuid of the active container, if there is an active container
    pub fn active_id(&self) -> Option<Uuid> {
        self.0.active_container
            .map(|active_ix| self.0.tree[active_ix].get_id())
    }

    pub fn lookup_view(&self, view: WlcView) -> Option<Uuid> {
        self.0.lookup_view(view).map(|c| c.get_id())
    }

    pub fn toggle_floating_focus(&mut self) -> CommandResult {
        self.0.toggle_floating_focus()
    }

    pub fn move_active(&mut self, maybe_uuid: Option<Uuid>, direction: Direction) -> CommandResult {
        let uuid = try!(maybe_uuid
                        .or_else(|| self.0.get_active_container()
                                 .and_then(|container| Some(container.get_id())))
                        .ok_or(TreeError::NoActiveContainer));
        try!(self.0.move_container(uuid, direction));
        // NOTE Make this not layout the active, but actually the node index's workspace.
        try!(self.layout_active_of(ContainerType::Output));
        Ok(())
    }

    /// Attempts to drag the window around the screen.
    pub fn try_drag_active(&mut self, point: Point) -> CommandResult {
        if let Some(mut action) = performing_action() {
            let old_point = action.grab;
            let active_ix = try!(self.0.active_container
                                .ok_or(TreeError::NoActiveContainer));
            try!(self.0.drag_floating(active_ix, point, old_point));
            action.grab = point;
            set_performing_action(Some(action));
            Ok(())
        } else {
            Err(TreeError::PerformingAction(false))
        }
    }

    /// Adds an Output to the tree. Never fails
    pub fn add_output(&mut self, output: WlcOutput) -> CommandResult {
        self.0.add_output(output);
        Ok(())
    }

    /// Adds a Workspace to the tree. Never fails
    pub fn switch_to_workspace(&mut self, name: &str) -> CommandResult {
        self.0.switch_to_workspace(name);
        Ok(())
    }

    /// Tiles the active container of some container type. Never fails
    pub fn layout_active_of(&mut self, c_type: ContainerType) -> CommandResult {
        self.0.layout_active_of(c_type);
        Ok(())
    }

    /// Attempts to set the node behind the id to be floating
    pub fn float_container(&mut self, id: Uuid) -> CommandResult {
        self.0.float_container(id)
    }

    /// Attempts to set the node behind the id to be not floating
    pub fn ground_container(&mut self, id: Uuid) -> CommandResult {
        self.0.ground_container(id)
    }

    /// Adds a view to the workspace of the active container
    pub fn add_view(&mut self, view: WlcView) -> CommandResult {
        let tree = &mut self.0;
        let output = view.get_output();
        if tree.get_active_container().is_none() {
            return Err(TreeError::NoActiveContainer)
        }
        view.set_mask(output.get_mask());
        let v_type = view.get_type();
        let v_class = view.get_class();
        // If it is empty, don't add to tree
        if v_type != ViewType::empty() {
            // Now focused on something outside the tree,
            // have to unset the active container
            if !tree.active_is_root() {
                tree.unset_active_container();
            }
            return Ok(())
        }
        if v_class.as_str() == "Background" {
            info!("Setting background: {}", view.get_title());
            view.send_to_back();
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Couldn't get output resolution");
            let fullscreen = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), fullscreen);
            return Ok(());
        }
        try!(tree.add_view(view));
        tree.normalize_view(view);
        tree.layout_active_of(ContainerType::Workspace);
        Ok(())
    }

    /// Attempts to remove a view from the tree. If it is not in the tree it fails.
    ///
    /// This will NOT close the handle behind the view, and should only be called
    /// on views that have already been slated for removal from the wlc pool.
    /// Otherwise you leak a `WlcView`
    pub fn remove_view(&mut self, view: WlcView) -> CommandResult {
        let result;
        match self.0.remove_view(&view) {
            Err(err)  => {
                warn!("Remove view error: {:?}\n {:#?}", err, *self.0);
                result = Err(err)
            },
            Ok(container) => {
                trace!("Removed container {:?}", container);
                result = Ok(())
            }
        }
        let root_ix = self.0.tree.root_ix();
        self.0.layout(root_ix);
        result
    }

    #[allow(dead_code)]
    /// Attempts to remove a container based on UUID. Fails if the container
    /// cannot be removed or if the container does not exist.
    ///
    /// This WILL close the view, and should never be called from the
    /// `view_destroyed` callback, as it's possible the view from that callback is invalid.
    pub fn remove_view_by_id(&mut self, id: Uuid) -> CommandResult {
        match try!(self.0.lookup(id)).get_handle() {
            Some(Handle::View(view)) => return self.remove_view(view),
            Some(Handle::Output(_)) | None => {
                Err(TreeError::UuidNotAssociatedWith(ContainerType::View))
            }
        }
    }

    /// Sets the view to be the new active container. Never fails
    pub fn set_active_view(&mut self, view: WlcView) -> CommandResult {
        try!(self.0.set_active_view(view.clone()));
        view.focus();
        Ok(())
    }

    #[allow(dead_code)]
    /// Sets the active container to be the container at the UUID
    /// Fails if the container is not a container or view, or if the
    /// container does not exist
    pub fn set_active_container_by_id(&mut self, id: Uuid) -> CommandResult {
        if let Some(node_ix) = self.0.tree.lookup_id(id) {
            match self.0.tree[node_ix].get_type() {
                ContainerType::View | ContainerType::Container => {
                    self.0.active_container = Some(node_ix);
                    Ok(())
                },
                _ => {
                    Err(TreeError::UuidWrongType(self.0.tree[node_ix].get_id(),
                                                  vec!(ContainerType::View,
                                                       ContainerType::Container)))
                }

            }
        } else {
            Err(TreeError::NodeNotFound(id))
        }
    }

    /// Destroy the tree
    pub fn destroy_tree(&mut self) -> CommandResult {
        self.0.destroy_tree();
        Ok(())
    }

    pub fn move_focus(&mut self, dir: Direction) -> CommandResult {
        try!(self.0.move_focus(dir));
        Ok(())
    }

    /// Moves the active container to a workspace
    pub fn send_active_to_workspace(&mut self, workspace_name: &str) -> CommandResult {
        self.0.send_active_to_workspace(workspace_name);
        Ok(())
    }

    /// Resizes the container, as if it was dragged at the edge to a certain point
    /// on the screen.
    pub fn resize_container(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point) -> CommandResult {
        match try_lock_action() {
            Ok(mut lock) => {
                if let Some(ref mut action) = *lock {
                    if try!(self.0.lookup(id)).floating() {
                        self.0.resize_floating(id, edge, pointer, action)
                    } else {
                        self.0.resize_tiled(id, edge, pointer, action)
                    }
                } else {
                    Err(TreeError::Action(ActionErr::ActionNotInProgress))
                }
            },
            _ => Err(TreeError::Action(ActionErr::ActionLocked))
        }
    }
}
<commit_msg>Removed stupid remove container debug statement<commit_after>//! Commands from the user to manipulate the tree

use super::{try_lock_tree, try_lock_action};
use super::{Action, ActionErr, Container, ContainerType, Direction, Handle, Layout, TreeError};
use super::Tree;

use uuid::Uuid;
use rustwlc::{Geometry, Point, ResizeEdge, WlcView, WlcOutput, ViewType};

pub type CommandResult = Result<(), TreeError>;

/* These commands are exported to take nothing and return nothing,
 * since they are the commands actually registered and usable over
 * the IPC/Lua thread.
 */

pub fn remove_active() {
    if let Ok(mut tree) = try_lock_tree() {
        if let Some(container) = tree.0.get_active_container_mut() {
            match *container {
                Container::View { ref handle, .. } => {
                    handle.close();
                    // Thanks borrowck
                    // Views shouldn't be removed from tree, that's handled by
                    // view_destroyed callback
                    return
                },
                _ => {}
            }
        }
        tree.0.remove_active();
    }
}

pub fn toggle_float() {
    if let Ok(mut tree) = try_lock_tree() {
        if let Some(uuid) = tree.active_id() {
            let is_floating = tree.0.lookup(uuid)
                .and_then(|container| Ok(container.floating()));
            let err = match is_floating {
                Ok(true) => tree.ground_container(uuid),
                Ok(false) => tree.float_container(uuid),
                Err(err) => Err(err)
            };
            if let Err(err) = err {
                warn!("{:?},\nError while toggling the floating of {:#?}\n {:#?}", err, uuid, *tree.0);
            }
        }
    }
}

pub fn toggle_float_focus() {
    if let Ok(mut tree) = try_lock_tree() {
        if let Err(err) = tree.toggle_floating_focus() {
            warn!("Could not float focus: {:#?}", err);
        }
    }
}

pub fn tile_switch() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_cardinal_tiling();
        tree.layout_active_of(ContainerType::Workspace)
            .unwrap_or_else(|_| {
                warn!("Could not tile workspace");
            });
    }
}

pub fn split_vertical() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_active_layout(Layout::Vertical).ok();
    }
}

pub fn split_horizontal() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.0.toggle_active_layout(Layout::Horizontal).ok();
    }
}

pub fn focus_left() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Left)
            .unwrap_or_else(|_| {
                warn!("Could not focus left");
            });
    }
}

pub fn focus_right() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Right)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            });
    }
}

pub fn focus_up() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Up)
            .unwrap_or_else(|_| {
                warn!("Could not focus up");
            });
    }
}

pub fn focus_down() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_focus(Direction::Down)
            .unwrap_or_else(|_| {
                warn!("Could not focus down");
            });
    }
}

pub fn move_active_left() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Left)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

pub fn move_active_right() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Right)
            .unwrap_or_else(|_| {
                error!("Could not focus right");
            })
    }
}

pub fn move_active_up() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Up)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

pub fn move_active_down() {
    if let Ok(mut tree) = try_lock_tree() {
        tree.move_active(None, Direction::Down)
            .unwrap_or_else(|_| {
                warn!("Could not focus right");
            })
    }
}

/// Returns a copy of the action behind the lock.
pub fn performing_action() -> Option<Action> {
    if let Ok(action) = try_lock_action() {
        *action
    } else {
        error!("Could not lock action mutex!");
        None
    }
}

/// Sets the value behind the lock to the provided value.
///
/// Note that this method blocks until the lock is released
///
/// None means an action is done being performed.
pub fn set_performing_action(val: Option<Action>) {
    if let Ok(mut action) = try_lock_action() {
        *action = val;
    } else {
        error!("Action mutex was poisoned");
        panic!("Action mutex was poisoned");
    }
}

/* These commands are the interface that the rest of Way Cooler has to the
 * tree. Any action done, whether through a callback, or from the IPC/Lua thread
 * it will have to go through one of these methods.
 */

impl Tree {
    /// Gets the uuid of the active container, if there is an active container
    pub fn active_id(&self) -> Option<Uuid> {
        self.0.active_container
            .map(|active_ix| self.0.tree[active_ix].get_id())
    }

    pub fn lookup_view(&self, view: WlcView) -> Option<Uuid> {
        self.0.lookup_view(view).map(|c| c.get_id())
    }

    pub fn toggle_floating_focus(&mut self) -> CommandResult {
        self.0.toggle_floating_focus()
    }

    pub fn move_active(&mut self, maybe_uuid: Option<Uuid>, direction: Direction) -> CommandResult {
        let uuid = try!(maybe_uuid
                        .or_else(|| self.0.get_active_container()
                                 .and_then(|container| Some(container.get_id())))
                        .ok_or(TreeError::NoActiveContainer));
        try!(self.0.move_container(uuid, direction));
        // NOTE Make this not layout the active, but actually the node index's workspace.
        try!(self.layout_active_of(ContainerType::Output));
        Ok(())
    }

    /// Attempts to drag the window around the screen.
    pub fn try_drag_active(&mut self, point: Point) -> CommandResult {
        if let Some(mut action) = performing_action() {
            let old_point = action.grab;
            let active_ix = try!(self.0.active_container
                                .ok_or(TreeError::NoActiveContainer));
            try!(self.0.drag_floating(active_ix, point, old_point));
            action.grab = point;
            set_performing_action(Some(action));
            Ok(())
        } else {
            Err(TreeError::PerformingAction(false))
        }
    }

    /// Adds an Output to the tree. Never fails
    pub fn add_output(&mut self, output: WlcOutput) -> CommandResult {
        self.0.add_output(output);
        Ok(())
    }

    /// Adds a Workspace to the tree. Never fails
    pub fn switch_to_workspace(&mut self, name: &str) -> CommandResult {
        self.0.switch_to_workspace(name);
        Ok(())
    }

    /// Tiles the active container of some container type. Never fails
    pub fn layout_active_of(&mut self, c_type: ContainerType) -> CommandResult {
        self.0.layout_active_of(c_type);
        Ok(())
    }

    /// Attempts to set the node behind the id to be floating
    pub fn float_container(&mut self, id: Uuid) -> CommandResult {
        self.0.float_container(id)
    }

    /// Attempts to set the node behind the id to be not floating
    pub fn ground_container(&mut self, id: Uuid) -> CommandResult {
        self.0.ground_container(id)
    }

    /// Adds a view to the workspace of the active container
    pub fn add_view(&mut self, view: WlcView) -> CommandResult {
        let tree = &mut self.0;
        let output = view.get_output();
        if tree.get_active_container().is_none() {
            return Err(TreeError::NoActiveContainer)
        }
        view.set_mask(output.get_mask());
        let v_type = view.get_type();
        let v_class = view.get_class();
        // If it is empty, don't add to tree
        if v_type != ViewType::empty() {
            // Now focused on something outside the tree,
            // have to unset the active container
            if !tree.active_is_root() {
                tree.unset_active_container();
            }
            return Ok(())
        }
        if v_class.as_str() == "Background" {
            info!("Setting background: {}", view.get_title());
            view.send_to_back();
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Couldn't get output resolution");
            let fullscreen = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), fullscreen);
            return Ok(());
        }
        try!(tree.add_view(view));
        tree.normalize_view(view);
        tree.layout_active_of(ContainerType::Workspace);
        Ok(())
    }

    /// Attempts to remove a view from the tree. If it is not in the tree it fails.
    ///
    /// This will NOT close the handle behind the view, and should only be called
    /// on views that have already been slated for removal from the wlc pool.
    /// Otherwise you leak a `WlcView`
    pub fn remove_view(&mut self, view: WlcView) -> CommandResult {
        let result;
        match self.0.remove_view(&view) {
            Err(err)  => {
                result = Err(err)
            },
            Ok(container) => {
                result = Ok(())
            }
        }
        let root_ix = self.0.tree.root_ix();
        self.0.layout(root_ix);
        result
    }

    #[allow(dead_code)]
    /// Attempts to remove a container based on UUID. Fails if the container
    /// cannot be removed or if the container does not exist.
    ///
    /// This WILL close the view, and should never be called from the
    /// `view_destroyed` callback, as it's possible the view from that callback is invalid.
    pub fn remove_view_by_id(&mut self, id: Uuid) -> CommandResult {
        match try!(self.0.lookup(id)).get_handle() {
            Some(Handle::View(view)) => return self.remove_view(view),
            Some(Handle::Output(_)) | None => {
                Err(TreeError::UuidNotAssociatedWith(ContainerType::View))
            }
        }
    }

    /// Sets the view to be the new active container. Never fails
    pub fn set_active_view(&mut self, view: WlcView) -> CommandResult {
        try!(self.0.set_active_view(view.clone()));
        view.focus();
        Ok(())
    }

    #[allow(dead_code)]
    /// Sets the active container to be the container at the UUID
    /// Fails if the container is not a container or view, or if the
    /// container does not exist
    pub fn set_active_container_by_id(&mut self, id: Uuid) -> CommandResult {
        if let Some(node_ix) = self.0.tree.lookup_id(id) {
            match self.0.tree[node_ix].get_type() {
                ContainerType::View | ContainerType::Container => {
                    self.0.active_container = Some(node_ix);
                    Ok(())
                },
                _ => {
                    Err(TreeError::UuidWrongType(self.0.tree[node_ix].get_id(),
                                                  vec!(ContainerType::View,
                                                       ContainerType::Container)))
                }

            }
        } else {
            Err(TreeError::NodeNotFound(id))
        }
    }

    /// Destroy the tree
    pub fn destroy_tree(&mut self) -> CommandResult {
        self.0.destroy_tree();
        Ok(())
    }

    pub fn move_focus(&mut self, dir: Direction) -> CommandResult {
        try!(self.0.move_focus(dir));
        Ok(())
    }

    /// Moves the active container to a workspace
    pub fn send_active_to_workspace(&mut self, workspace_name: &str) -> CommandResult {
        self.0.send_active_to_workspace(workspace_name);
        Ok(())
    }

    /// Resizes the container, as if it was dragged at the edge to a certain point
    /// on the screen.
    pub fn resize_container(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point) -> CommandResult {
        match try_lock_action() {
            Ok(mut lock) => {
                if let Some(ref mut action) = *lock {
                    if try!(self.0.lookup(id)).floating() {
                        self.0.resize_floating(id, edge, pointer, action)
                    } else {
                        self.0.resize_tiled(id, edge, pointer, action)
                    }
                } else {
                    Err(TreeError::Action(ActionErr::ActionNotInProgress))
                }
            },
            _ => Err(TreeError::Action(ActionErr::ActionLocked))
        }
    }
}
<|endoftext|>


<commit_before>mod advent_of_code;

use advent_of_code::get_line;
use advent_of_code::get_pieces;
use advent_of_code::parse_single_number;

use std::io;

use std::str::FromStr;

enum Direction {
    North,
    East,
    South,
    West,
}

fn turn_left(current_direction: Direction)
    -> Direction
{
    match current_direction {
        Direction::North => Direction::West,
        Direction::West => Direction::South,
        Direction::South => Direction::East,
        Direction::East => Direction::North,
    }
}

fn turn_right(current_direction: Direction)
    -> Direction
{
    match current_direction {
        Direction::West => Direction::North,
        Direction::South => Direction::West,
        Direction::East => Direction::South,
        Direction::North => Direction::East,
    }
}

pub fn main()
{
    let stdin = io::stdin();
    let pieces = get_pieces(get_line(stdin.lock()));

    let mut delta_east = 0;
    let mut delta_north = 0;

    let mut facing_direction = Direction::North;

    for piece in pieces
    {
        if piece.starts_with('R')
        {
            facing_direction = turn_right(facing_direction);
        }
        else if piece.starts_with('L')
        {
            facing_direction = turn_left(facing_direction);
        }
        else
        {
            panic!("Unexpected input ({:?}) does not start with L or R.");
        }

        let rest = String::from_str(&piece[1..]).unwrap();
        let num = parse_single_number(rest);

        match facing_direction {
            Direction::North => delta_north += num,
            Direction::East => delta_east += num,
            Direction::South => delta_north -= num,
            Direction::West => delta_east -= num,
        }
    }

    let total = delta_north + delta_east;
    println!("{:?} North, {:?} East: {:?} Total", delta_north, delta_east, total);
}
<commit_msg>Ensure distances are positive before combining<commit_after>mod advent_of_code;

use advent_of_code::get_line;
use advent_of_code::get_pieces;
use advent_of_code::parse_single_number;

use std::io;

use std::str::FromStr;

enum Direction {
    North,
    East,
    South,
    West,
}

fn turn_left(current_direction: Direction)
    -> Direction
{
    match current_direction {
        Direction::North => Direction::West,
        Direction::West => Direction::South,
        Direction::South => Direction::East,
        Direction::East => Direction::North,
    }
}

fn turn_right(current_direction: Direction)
    -> Direction
{
    match current_direction {
        Direction::West => Direction::North,
        Direction::South => Direction::West,
        Direction::East => Direction::South,
        Direction::North => Direction::East,
    }
}

pub fn main()
{
    let stdin = io::stdin();
    let pieces = get_pieces(get_line(stdin.lock()));

    let mut delta_east = 0;
    let mut delta_north = 0;

    let mut facing_direction = Direction::North;

    for piece in pieces
    {
        if piece.starts_with('R')
        {
            facing_direction = turn_right(facing_direction);
        }
        else if piece.starts_with('L')
        {
            facing_direction = turn_left(facing_direction);
        }
        else
        {
            panic!("Unexpected input ({:?}) does not start with L or R.");
        }

        let rest = String::from_str(&piece[1..]).unwrap();
        let num = parse_single_number(rest);

        match facing_direction {
            Direction::North => delta_north += num,
            Direction::East => delta_east += num,
            Direction::South => delta_north -= num,
            Direction::West => delta_east -= num,
        }
    }

    let total = delta_north.abs() + delta_east.abs();
    println!("{:?} North, {:?} East: {:?} Total", delta_north, delta_east, total);
}
<|endoftext|>


<commit_before>use piston_window::UpdateArgs;

use player::Player;
use settings::Settings;
use ship::ShipDirection;

pub struct App<'a> {
    pub settings: &'a Settings,
    players: [Player<'a>; 2],
    pub state: GameState,
    turn: u8,
    pub turn_active: bool,
    winner: Option<u8>,
    pub turn_end_timer: f64,
    pub cpu_turn_timer: f64,
    pub grid_area: [u32; 4],
    pub window_size: [u32; 2],
    mouse_cursor: [f64; 2],
}

impl<'a> App<'a> {
    pub fn new(settings: &Settings) -> App {
        let grid_area = [
            settings.space_size,
            settings.space_size * 3,
            settings.spaces_x as u32 * settings.space_size,
            settings.spaces_y as u32 * settings.space_size
        ];

        let window_size = [
            grid_area[2] + settings.space_size * 2,
            grid_area[3] + settings.space_size * 4
        ];

        App {
            settings: &settings,
            players: [
                Player::new(&settings, false),
                Player::new(&settings, true)
            ],
            state: GameState::ShipPlacement,
            turn: 0,
            turn_active: true,
            winner: None,
            turn_end_timer: 0.0,
            cpu_turn_timer: 0.0,
            grid_area: grid_area,
            window_size: window_size,
            mouse_cursor: [0.0; 2],
        }
    }

    pub fn update(&mut self, u: &UpdateArgs) {
        if self.state == GameState::ShipPlacement {
            if self.players[self.turn as usize].is_cpu {
                self.players[self.turn as usize].cpu_place_ships();
            }

            if self.players[self.turn as usize].ships().len() == 4 {
                self.switch_turn();
            }

            // All ships have been placed; start the game.
            if self.players[0].ships().len() == 4 && self.players[1].ships().len() == 4 {
                self.state = GameState::Active;
            }
        } else if self.state == GameState::Active || self.state == GameState::Over {
            if !self.turn_active && self.winner.is_none() {

                // Continue/end the end-of-turn delay.
                if self.turn_end_timer < 1.5 {
                    self.turn_end_timer += u.dt;
                } else {
                    if self.state == GameState::Active {
                        self.switch_turn();
                    } else {
                        self.winner = Some(self.turn);
                    }
                }
            }

            // Continue/end the delay when CPU players take their turn.
            if self.turn_active && self.players[self.turn as usize].is_cpu {
                self.cpu_turn_timer += u.dt;
                if self.cpu_turn_timer >= 1.0 {
                    self.cpu_turn_timer = 0.0;
                    let ref mut opponent = self.players[self.not_turn()];
                    let cpu_space = opponent.cpu_select_space();
                    self.state = opponent.select_space(&cpu_space);
                    self.turn_active = false;
                }
            }
        }
    }

    /// Provides a reference to the currently active player.
    pub fn active_player(&self) -> &Player {
        &self.players[self.turn as usize]
    }

    /// Provides a reference to the currently inactive player.
    pub fn inactive_player(&self) -> &Player {
        &self.players[self.not_turn()]
    }

    /// Returns as `usize` the index of the currently active player.
    pub fn turn(&self) -> usize {
        self.turn as usize
    }

    /// Returns as `usize` the index of the currently inactive player.
    pub fn not_turn(&self) -> usize {
        (self.turn + 1) as usize % 2
    }

    /// When a player's turn is finished, this sets the other player as active.
    fn switch_turn(&mut self) {
        self.turn = self.not_turn() as u8;
        self.turn_active = true;
        self.turn_end_timer = 0.0;
    }

    /// Returns true if it is currently a human player's turn.
    fn is_player_turn(&self) -> bool {
        self.turn_active && !self.players[self.turn as usize].is_cpu
    }

    /// Returns as `usize` the winner, if there is one.
    pub fn get_winner(&self) -> Option<usize> {
        match self.winner {
            Some(w) => Some(w as usize),
            None => None
        }
    }

    /// Selects a position on the opponent's grid if it is unchecked.
    fn select_opponent_space(&mut self, pos: &[u8; 2]) {
        let ref mut opponent = self.players[self.not_turn()];
        if opponent.space(pos).is_unchecked() {
            self.state = opponent.select_space(pos);
            self.turn_active = false;
        }
    }

    /// Processes left button presses according to the current program state.
    pub fn button_left(&mut self) {
        if self.state == GameState::ShipPlacement && self.is_player_turn() {
            self.players[self.turn as usize].move_temp_ship(ShipDirection::West);
        }

        if self.state == GameState::Active && self.is_player_turn() {
            self.players[self.turn as usize].move_grid_cursor(ShipDirection::West);
        }
    }

    /// Processes right button presses according to the current program state.
    pub fn button_right(&mut self) {
        if self.state == GameState::ShipPlacement && self.is_player_turn() {
            self.players[self.turn as usize].move_temp_ship(ShipDirection::East);
        }

        if self.state == GameState::Active && self.is_player_turn() {
            self.players[self.turn as usize].move_grid_cursor(ShipDirection::East);
        }
    }

    /// Processes up button presses according to the current program state.
    pub fn button_up(&mut self) {
        if self.state == GameState::ShipPlacement && self.is_player_turn() {
            self.players[self.turn as usize].move_temp_ship(ShipDirection::North);
        }

        if self.state == GameState::Active && self.is_player_turn() {
            self.players[self.turn as usize].move_grid_cursor(ShipDirection::North);
        }
    }

    /// Processes down button presses according to the current program state.
    pub fn button_down(&mut self) {
        if self.state == GameState::ShipPlacement && self.is_player_turn() {
            self.players[self.turn as usize].move_temp_ship(ShipDirection::South);
        }

        if self.state == GameState::Active && self.is_player_turn() {
            self.players[self.turn as usize].move_grid_cursor(ShipDirection::South);
        }
    }

    /// Processes primary button presses according to the current program state.
    pub fn button_primary(&mut self) {
        if self.state == GameState::ShipPlacement && self.is_player_turn() {
            self.players[self.turn as usize].place_temp_ship();
        }

        if self.state == GameState::Active && self.is_player_turn() {
            let grid_pos = self.players[self.turn as usize].get_grid_cursor();
            self.select_opponent_space(&grid_pos);
        }
    }

    /// Processes secondary button presses according to the current program state.
    pub fn button_secondary(&mut self) {
        if self.state == GameState::ShipPlacement && self.is_player_turn() {
            self.players[self.turn as usize].rotate_temp_ship();
        }
    }

    /// Processes left mouse clicks according to the current program state.
    pub fn mouse_left_click(&mut self) {
        if let Some(grid_pos) = self.mouse_cursor_grid_position() {
            if self.state == GameState::ShipPlacement && self.is_player_turn() {
                self.players[self.turn as usize].place_temp_ship();
            }

            if self.state == GameState::Active && self.is_player_turn() {
                self.select_opponent_space(&grid_pos);
            }
        }
    }

    /// Records the last known mouse cursor position.
    pub fn mouse_cursor_movement(&mut self, c: &[f64; 2]) {
        self.mouse_cursor = *c;

        if let Some(grid_pos) = self.mouse_cursor_grid_position() {
            let is_player_turn = self.is_player_turn();
            let ref mut player = self.players[self.turn as usize];

            if self.state == GameState::ShipPlacement {
                if let Some(ship) = player.get_ship_position(
                    grid_pos,
                    player.temp_ship_dir,
                    player.ships().len() as u8 + 2
                ) {
                    player.temp_ship_pos = ship;
                }
            }

            if self.state == GameState::Active && is_player_turn {
                player.set_grid_cursor(&grid_pos);
            }
        }
    }

    /// Returns the grid coordinates of the mouse cursor position.
    fn mouse_cursor_grid_position(&self) -> Option<[u8; 2]> {
        let position: Option<[u8; 2]>;
        if self.mouse_cursor[0] >= self.grid_area[0] as f64
            && self.mouse_cursor[1] >= self.grid_area[1] as f64
            && self.mouse_cursor[0] < (self.grid_area[0] + self.grid_area[2]) as f64
            && self.mouse_cursor[1] < (self.grid_area[1] + self.grid_area[3]) as f64
        {
            position = Some([
                ((self.mouse_cursor[0] - self.grid_area[0] as f64) / self.settings.space_size as f64) as u8,
                ((self.mouse_cursor[1] - self.grid_area[1] as f64) / self.settings.space_size as f64) as u8,
            ]);
        } else {
            position = None;
        }

        position
    }
}

#[derive(PartialEq)]
pub enum GameState {
    ShipPlacement,
    Active,
    Over
}

<commit_msg>Clean up code duplication across button methods<commit_after>use piston_window::UpdateArgs;

use player::Player;
use settings::Settings;
use ship::ShipDirection;

pub struct App<'a> {
    pub settings: &'a Settings,
    players: [Player<'a>; 2],
    pub state: GameState,
    turn: u8,
    pub turn_active: bool,
    winner: Option<u8>,
    pub turn_end_timer: f64,
    pub cpu_turn_timer: f64,
    pub grid_area: [u32; 4],
    pub window_size: [u32; 2],
    mouse_cursor: [f64; 2],
}

impl<'a> App<'a> {
    pub fn new(settings: &Settings) -> App {
        let grid_area = [
            settings.space_size,
            settings.space_size * 3,
            settings.spaces_x as u32 * settings.space_size,
            settings.spaces_y as u32 * settings.space_size
        ];

        let window_size = [
            grid_area[2] + settings.space_size * 2,
            grid_area[3] + settings.space_size * 4
        ];

        App {
            settings: &settings,
            players: [
                Player::new(&settings, false),
                Player::new(&settings, true)
            ],
            state: GameState::ShipPlacement,
            turn: 0,
            turn_active: true,
            winner: None,
            turn_end_timer: 0.0,
            cpu_turn_timer: 0.0,
            grid_area: grid_area,
            window_size: window_size,
            mouse_cursor: [0.0; 2],
        }
    }

    pub fn update(&mut self, u: &UpdateArgs) {
        if self.state == GameState::ShipPlacement {
            if self.players[self.turn as usize].is_cpu {
                self.players[self.turn as usize].cpu_place_ships();
            }

            if self.players[self.turn as usize].ships().len() == 4 {
                self.switch_turn();
            }

            // All ships have been placed; start the game.
            if self.players[0].ships().len() == 4 && self.players[1].ships().len() == 4 {
                self.state = GameState::Active;
            }
        } else if self.state == GameState::Active || self.state == GameState::Over {
            if !self.turn_active && self.winner.is_none() {

                // Continue/end the end-of-turn delay.
                if self.turn_end_timer < 1.5 {
                    self.turn_end_timer += u.dt;
                } else {
                    if self.state == GameState::Active {
                        self.switch_turn();
                    } else {
                        self.winner = Some(self.turn);
                    }
                }
            }

            // Continue/end the delay when CPU players take their turn.
            if self.turn_active && self.players[self.turn as usize].is_cpu {
                self.cpu_turn_timer += u.dt;
                if self.cpu_turn_timer >= 1.0 {
                    self.cpu_turn_timer = 0.0;
                    let ref mut opponent = self.players[self.not_turn()];
                    let cpu_space = opponent.cpu_select_space();
                    self.state = opponent.select_space(&cpu_space);
                    self.turn_active = false;
                }
            }
        }
    }

    /// Provides a reference to the currently active player.
    pub fn active_player(&self) -> &Player {
        &self.players[self.turn as usize]
    }

    /// Provides a reference to the currently inactive player.
    pub fn inactive_player(&self) -> &Player {
        &self.players[self.not_turn()]
    }

    /// Returns as `usize` the index of the currently active player.
    pub fn turn(&self) -> usize {
        self.turn as usize
    }

    /// Returns as `usize` the index of the currently inactive player.
    pub fn not_turn(&self) -> usize {
        (self.turn + 1) as usize % 2
    }

    /// When a player's turn is finished, this sets the other player as active.
    fn switch_turn(&mut self) {
        self.turn = self.not_turn() as u8;
        self.turn_active = true;
        self.turn_end_timer = 0.0;
    }

    /// Returns true if it is currently a human player's turn.
    fn is_player_turn(&self) -> bool {
        self.turn_active && !self.players[self.turn as usize].is_cpu
    }

    /// Checks if a human player is currently placing ships.
    fn is_player_placing_ship(&self) -> bool {
        self.state == GameState::ShipPlacement && self.is_player_turn()
    }

    /// Checks if a human player is currently selecting a space.
    fn is_player_selecting_space(&self) -> bool {
        self.state == GameState::Active && self.is_player_turn()
    }

    /// Returns as `usize` the winner, if there is one.
    pub fn get_winner(&self) -> Option<usize> {
        match self.winner {
            Some(w) => Some(w as usize),
            None => None
        }
    }

    /// Selects a position on the opponent's grid if it is unchecked.
    fn select_opponent_space(&mut self, pos: &[u8; 2]) {
        let ref mut opponent = self.players[self.not_turn()];
        if opponent.space(pos).is_unchecked() {
            self.state = opponent.select_space(pos);
            self.turn_active = false;
        }
    }

    /// Performs grid movement according to the current program state.
    fn movement(&mut self, direction: ShipDirection) {
        if self.is_player_placing_ship() {
            self.players[self.turn as usize].move_temp_ship(direction);
        }

        if self.is_player_selecting_space() {
            self.players[self.turn as usize].move_grid_cursor(direction);
        }
    }

    fn primary_action(&mut self, grid_pos: &[u8; 2]) {
        if self.is_player_placing_ship() {
            self.players[self.turn as usize].place_temp_ship();
        }

        if self.is_player_selecting_space() {
            self.select_opponent_space(grid_pos);
        }
    }

    /// Processes left button presses according to the current program state.
    pub fn button_left(&mut self) {
        self.movement(ShipDirection::West);
    }

    /// Processes right button presses according to the current program state.
    pub fn button_right(&mut self) {
        self.movement(ShipDirection::East);
    }

    /// Processes up button presses according to the current program state.
    pub fn button_up(&mut self) {
        self.movement(ShipDirection::North);
    }

    /// Processes down button presses according to the current program state.
    pub fn button_down(&mut self) {
        self.movement(ShipDirection::South);
    }

    /// Processes primary button presses according to the current program state.
    pub fn button_primary(&mut self) {
        let grid_pos = self.players[self.turn as usize].get_grid_cursor();
        self.primary_action(&grid_pos);
    }

    /// Processes secondary button presses according to the current program state.
    pub fn button_secondary(&mut self) {
        if self.is_player_placing_ship() {
            self.players[self.turn as usize].rotate_temp_ship();
        }
    }

    /// Processes left mouse clicks according to the current program state.
    pub fn mouse_left_click(&mut self) {
        if let Some(grid_pos) = self.mouse_cursor_grid_position() {
            self.primary_action(&grid_pos);
        }
    }

    /// Records the last known mouse cursor position.
    pub fn mouse_cursor_movement(&mut self, c: &[f64; 2]) {
        self.mouse_cursor = *c;

        if let Some(grid_pos) = self.mouse_cursor_grid_position() {
            let is_player_turn = self.is_player_turn();
            let ref mut player = self.players[self.turn as usize];

            if self.state == GameState::ShipPlacement {
                if let Some(ship) = player.get_ship_position(
                    grid_pos,
                    player.temp_ship_dir,
                    player.ships().len() as u8 + 2
                ) {
                    player.temp_ship_pos = ship;
                }
            }

            if self.state == GameState::Active && is_player_turn {
                player.set_grid_cursor(&grid_pos);
            }
        }
    }

    /// Returns the grid coordinates of the mouse cursor position.
    fn mouse_cursor_grid_position(&self) -> Option<[u8; 2]> {
        let position: Option<[u8; 2]>;
        if self.mouse_cursor[0] >= self.grid_area[0] as f64
            && self.mouse_cursor[1] >= self.grid_area[1] as f64
            && self.mouse_cursor[0] < (self.grid_area[0] + self.grid_area[2]) as f64
            && self.mouse_cursor[1] < (self.grid_area[1] + self.grid_area[3]) as f64
        {
            position = Some([
                ((self.mouse_cursor[0] - self.grid_area[0] as f64) / self.settings.space_size as f64) as u8,
                ((self.mouse_cursor[1] - self.grid_area[1] as f64) / self.settings.space_size as f64) as u8,
            ]);
        } else {
            position = None;
        }

        position
    }
}

#[derive(PartialEq)]
pub enum GameState {
    ShipPlacement,
    Active,
    Over
}

<|endoftext|>


<commit_before>use super::interconnect::Interconnect;
use super::interconnect::END_RESERVED;

const INSTRUCTION_SIZE: u16 = 2;

#[derive(Default, Debug)]
pub struct Cpu {
    // Interconnect is used to control system resources like rom and memory.
    interconnect: Interconnect,

    // Program counter.
    pc: u16,

    // The function call stack.
    stack: [u16; 16],

    // Stack pointer.
    sp: u8,

    // General purpose registers v0-vf.
    v0: u8,
    v1: u8,
    v2: u8,
    v3: u8,
    v4: u8,
    v5: u8,
    v6: u8,
    v7: u8,
    v8: u8,
    v9: u8,
    va: u8,
    vb: u8,
    vc: u8,
    vd: u8,
    ve: u8,
    vf: u8,

    // Address register "I".
    i: u16,

    // Timer and sound registers.
    dt: u8,
    st: u8,
}

impl Cpu {
    pub fn new(interconnect: Interconnect) -> Cpu {
        Cpu {
            interconnect: interconnect,
            pc: END_RESERVED as u16,
            ..Cpu::default()
        }
    }

    /// Execute instructions from ram.
    pub fn run(&mut self) {
        loop {
            let word = self.interconnect.read_word(self.pc);

            // Execute until the subroutine ends.
            if self.execute_instruction(word) {
                break
            }
        }
    }

    #[inline(always)]
    fn execute_instruction(&mut self, instr: u16) -> bool {
        let opcode = (instr >> 12) as u8;
        let mut ret: bool = false;

        match opcode {
            0x0 => {
                let identifier = ((instr << 8) >> 8) as u8;

                match identifier {
                    0xE0 => {
                        // 00E0 - CLS
                        // Clears the screen.

                        self.interconnect.clear_display();
                    },
                    0xEE => {
                        // 00EE - RET
                        // Returns from a subroutine.

                        self.sp -= 1;
                        self.pc = self.stack[self.sp as usize];
                        self.stack[self.sp as usize] = 0;

                        // Break out of the execution loop for the current
                        // subroutine.
                        ret = true;
                    },
                    _ => {
                        println!("cpu: {:#?}", self);
                        panic!("Found unknown identifier at instruction: {:#x}, addr: {:#x}", instr, self.pc);
                    },
                }
            },
            0x2 => {
                // 2NNN - CALL NNN
                //
                // Calls subroutine at NNN.

                let addr = ((instr << 4) >> 4) as u16;

                // Add the current program counter to the call stack.
                self.stack[self.sp as usize] = self.pc;
                self.sp += 1;

                // Set the program counter to the call address begin executing
                // the subroutine.
                self.pc = addr;
                self.run();
            },
            0x6 => {
                // 6XNN - LD VX, NN
                //
                // Sets VX to NN.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;
                self.set_reg(regx, byte);
            },
            0x7 => {
                // 7XNN - ADD VX, NN
                //
                // Adds NN to VX.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;

                let result = self.get_reg(regx) + byte;
                self.set_reg(regx, result);
            },
            0xa => {
                // ANNN - LD I, NNN
                //
                // Sets I to the address NNN.

                let addr = ((instr << 4) >> 4) as u16;
                self.i = addr;
            },
            0xd => {
                // DXYN - DRW VX, VY, N
                //
                // Sprites stored in memory at location in index register (I),
                // 8bits wide. Wraps around the screen. If when drawn, clears a
                // pixel, register VF is set to 1 otherwise it is zero.
                //
                // All drawing is XOR drawing (i.e. it toggles the screen
                // pixels). Sprites are drawn starting at position VX, VY. N is
                // the number of 8bit rows that need to be drawn. If N is
                // greater than 1, second line continues at position VX, VY+1,
                // and so on.

                let regx = ((instr << 4) >> 12) as u8;
                let regy = ((instr << 8) >> 12) as u8;
                let nibble = ((instr << 12) >> 12) as usize;

                // Read N (nibble) bytes out out of memory starting at address
                // register I into our sprite.
                let mut sprite = vec![0 as u8; nibble];
                for i in 0..nibble {
                    sprite[i] = self.interconnect.ram[self.i as usize + i];
                }

                // Get screen coordinates from the requested registers.
                let x = self.get_reg(regx);
                let y = self.get_reg(regy);

                // Draw the sprite and store collision detection results in vf.
                self.vf = self.interconnect.draw(x as usize, y as usize, sprite);
            },
            0xf => {
                let regx = ((instr << 4) >> 12) as u8;
                let identifier = ((instr << 8) >> 8) as u8;

                match identifier {
                    0x29 => {
                        // FX29 - LD F, VX
                        //
                        // Sets I to the location of the sprite for the
                        // character in VX. Characters 0-F (in hexadecimal) are
                        // represented by a 4x5 font.

                        let x: u8 = self.get_reg(regx);
                        self.i = self.interconnect.get_font(x);
                    },
                    0x33 => {
                        // FX33 - LD B, VX
                        //
                        // Stores the Binary-coded decimal representation of VX,
                        // with the most significant of three digits at the
                        // address in I, the middle digit at I plus 1, and the
                        // least significant digit at I plus 2. (In other words,
                        // take the decimal representation of VX, place the
                        // hundreds digit in memory at location in I, the tens
                        // digit at location I+1, and the ones digit at
                        // location I+2.)

                        const DECIMAL_LENGTH: usize = 3;

                        let mut x: u8 = self.get_reg(regx);
                        let mut digits = vec![0 as u8; DECIMAL_LENGTH];
                        let mut digit_count: usize = 0;

                        // Organize the digits in the decimal into a slice.
                        while x > 0 {
                            digit_count += 1;
                            digits[DECIMAL_LENGTH - digit_count] = x % 10;
                            x /= 10;
                        }

                        // Set I, I+1, and I+3 to the values of the digits.
                        let i: usize = self.i as usize;
                        self.interconnect.ram[i] = digits[0];
                        self.interconnect.ram[i + 1] = digits[1];
                        self.interconnect.ram[i + 2] = digits[2];
                    },
                    0x65 => {
                        // FX65 - LD VX, [I]
                        //
                        // Fills V0 to VX with values from memory starting at
                        // address I.

                        let i: usize = self.i as usize;
                        let end_reg = (regx + 1) as usize;

                        for register in 0x0..end_reg {
                            let mem = self.interconnect.ram[i + register];
                            self.set_reg(register as u8, mem);
                        }
                    },
                    _ => {
                        println!("cpu: {:#?}", self);
                        panic!("Found unknown identifier at instruction: {:#x}, addr: {:#x}", instr, self.pc);
                    },
                }
            },
            _ => {
                println!("cpu: {:#?}", self);
                panic!("Found unknown opcode at instruction: {:#x}, addr: {:#x}", instr, self.pc);
            },
        }

        // Increment the program counter to the next instruction.
        if !ret {
            self.pc += INSTRUCTION_SIZE;
        }

        // By default the execution loop in not broken. True will be returned
        // only by a successful RET instruction is executed.
        ret
    }

    /// Gets the value at a specified register.
    fn get_reg(&mut self, reg: u8) -> u8 {
        match reg {
            0x0 => self.v0,
            0x1 => self.v1,
            0x2 => self.v2,
            0x3 => self.v3,
            0x4 => self.v4,
            0x5 => self.v5,
            0x6 => self.v6,
            0x7 => self.v7,
            0x8 => self.v8,
            0x9 => self.v9,
            0xa => self.va,
            0xb => self.vb,
            0xc => self.vc,
            0xd => self.vd,
            0xe => self.ve,
            0xf => self.vf,
            _ => {
                panic!("Cannot get unknown register: V{:X}", reg);
            }
        }
    }

    /// Sets the value of a general purpose register.
    fn set_reg(&mut self, reg: u8, byte: u8) {
        match reg {
            0x0 => self.v0 = byte,
            0x1 => self.v1 = byte,
            0x2 => self.v2 = byte,
            0x3 => self.v3 = byte,
            0x4 => self.v4 = byte,
            0x5 => self.v5 = byte,
            0x6 => self.v6 = byte,
            0x7 => self.v7 = byte,
            0x8 => self.v8 = byte,
            0x9 => self.v9 = byte,
            0xa => self.va = byte,
            0xb => self.vb = byte,
            0xc => self.vc = byte,
            0xd => self.vd = byte,
            0xe => self.ve = byte,
            0xf => self.vf = byte,
            _ => {
                panic!("Cannot set unknown register: V{:X}", reg);
            }
        }
    }
}
<commit_msg>Added DT operations<commit_after>use super::interconnect::Interconnect;
use super::interconnect::END_RESERVED;

const INSTRUCTION_SIZE: u16 = 2;

#[derive(Default, Debug)]
pub struct Cpu {
    // Interconnect is used to control system resources like rom and memory.
    interconnect: Interconnect,

    // Program counter.
    pc: u16,

    // The function call stack.
    stack: [u16; 16],

    // Stack pointer.
    sp: u8,

    // General purpose registers v0-vf.
    v0: u8,
    v1: u8,
    v2: u8,
    v3: u8,
    v4: u8,
    v5: u8,
    v6: u8,
    v7: u8,
    v8: u8,
    v9: u8,
    va: u8,
    vb: u8,
    vc: u8,
    vd: u8,
    ve: u8,
    vf: u8,

    // Address register "I".
    i: u16,

    // Timer and sound registers.
    dt: u8,
    st: u8,
}

impl Cpu {
    pub fn new(interconnect: Interconnect) -> Cpu {
        Cpu {
            interconnect: interconnect,
            pc: END_RESERVED as u16,
            ..Cpu::default()
        }
    }

    /// Execute instructions from ram.
    pub fn run(&mut self) {
        loop {
            let word = self.interconnect.read_word(self.pc);

            // Execute until the subroutine ends.
            if self.execute_instruction(word) {
                break
            }
        }
    }

    #[inline(always)]
    fn execute_instruction(&mut self, instr: u16) -> bool {
        let opcode = (instr >> 12) as u8;
        let mut ret: bool = false;

        match opcode {
            0x0 => {
                let identifier = ((instr << 8) >> 8) as u8;

                match identifier {
                    0xE0 => {
                        // 00E0 - CLS
                        // Clears the screen.

                        self.interconnect.clear_display();
                    },
                    0xEE => {
                        // 00EE - RET
                        // Returns from a subroutine.

                        self.sp -= 1;
                        self.pc = self.stack[self.sp as usize];
                        self.stack[self.sp as usize] = 0;

                        // Break out of the execution loop for the current
                        // subroutine.
                        ret = true;
                    },
                    _ => {
                        println!("cpu: {:#?}", self);
                        panic!("Found unknown identifier at instruction: {:#x}, addr: {:#x}", instr, self.pc);
                    },
                }
            },
            0x2 => {
                // 2NNN - CALL NNN
                //
                // Calls subroutine at NNN.

                let addr = ((instr << 4) >> 4) as u16;

                // Add the current program counter to the call stack.
                self.stack[self.sp as usize] = self.pc;
                self.sp += 1;

                // Set the program counter to the call address begin executing
                // the subroutine.
                self.pc = addr;
                self.run();
            },
            0x6 => {
                // 6XNN - LD VX, NN
                //
                // Sets VX to NN.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;
                self.set_reg(regx, byte);
            },
            0x7 => {
                // 7XNN - ADD VX, NN
                //
                // Adds NN to VX.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;

                let result = self.get_reg(regx) + byte;
                self.set_reg(regx, result);
            },
            0xa => {
                // ANNN - LD I, NNN
                //
                // Sets I to the address NNN.

                let addr = ((instr << 4) >> 4) as u16;
                self.i = addr;
            },
            0xd => {
                // DXYN - DRW VX, VY, N
                //
                // Sprites stored in memory at location in index register (I),
                // 8bits wide. Wraps around the screen. If when drawn, clears a
                // pixel, register VF is set to 1 otherwise it is zero.
                //
                // All drawing is XOR drawing (i.e. it toggles the screen
                // pixels). Sprites are drawn starting at position VX, VY. N is
                // the number of 8bit rows that need to be drawn. If N is
                // greater than 1, second line continues at position VX, VY+1,
                // and so on.

                let regx = ((instr << 4) >> 12) as u8;
                let regy = ((instr << 8) >> 12) as u8;
                let nibble = ((instr << 12) >> 12) as usize;

                // Read N (nibble) bytes out out of memory starting at address
                // register I into our sprite.
                let mut sprite = vec![0 as u8; nibble];
                for i in 0..nibble {
                    sprite[i] = self.interconnect.ram[self.i as usize + i];
                }

                // Get screen coordinates from the requested registers.
                let x = self.get_reg(regx);
                let y = self.get_reg(regy);

                // Draw the sprite and store collision detection results in vf.
                self.vf = self.interconnect.draw(x as usize, y as usize, sprite);
            },
            0xf => {
                let regx = ((instr << 4) >> 12) as u8;
                let identifier = ((instr << 8) >> 8) as u8;

                match identifier {
                    0x07 => {
                        // FX07 - LD VX, DT
                        //
                        // Sets VX to the value of the delay timer.

                        let dt = self.dt;
                        self.set_reg(regx, dt);
                    },
                    0x15 => {
                        // FX15 - LD DT, VX
                        //
                        // Sets the delay timer to VX.

                        let x: u8 = self.get_reg(regx);
                        self.dt = x;
                    },
                    0x29 => {
                        // FX29 - LD F, VX
                        //
                        // Sets I to the location of the sprite for the
                        // character in VX. Characters 0-F (in hexadecimal) are
                        // represented by a 4x5 font.

                        let x: u8 = self.get_reg(regx);
                        self.i = self.interconnect.get_font(x);
                    },
                    0x33 => {
                        // FX33 - LD B, VX
                        //
                        // Stores the Binary-coded decimal representation of VX,
                        // with the most significant of three digits at the
                        // address in I, the middle digit at I plus 1, and the
                        // least significant digit at I plus 2. (In other words,
                        // take the decimal representation of VX, place the
                        // hundreds digit in memory at location in I, the tens
                        // digit at location I+1, and the ones digit at
                        // location I+2.)

                        const DECIMAL_LENGTH: usize = 3;

                        let mut x: u8 = self.get_reg(regx);
                        let mut digits = vec![0 as u8; DECIMAL_LENGTH];
                        let mut digit_count: usize = 0;

                        // Organize the digits in the decimal into a slice.
                        while x > 0 {
                            digit_count += 1;
                            digits[DECIMAL_LENGTH - digit_count] = x % 10;
                            x /= 10;
                        }

                        // Set I, I+1, and I+3 to the values of the digits.
                        let i: usize = self.i as usize;
                        self.interconnect.ram[i] = digits[0];
                        self.interconnect.ram[i + 1] = digits[1];
                        self.interconnect.ram[i + 2] = digits[2];
                    },
                    0x65 => {
                        // FX65 - LD VX, [I]
                        //
                        // Fills V0 to VX with values from memory starting at
                        // address I.

                        let i: usize = self.i as usize;
                        let end_reg = (regx + 1) as usize;

                        for register in 0x0..end_reg {
                            let mem = self.interconnect.ram[i + register];
                            self.set_reg(register as u8, mem);
                        }
                    },
                    _ => {
                        println!("cpu: {:#?}", self);
                        panic!("Found unknown identifier at instruction: {:#x}, addr: {:#x}", instr, self.pc);
                    },
                }
            },
            _ => {
                println!("cpu: {:#?}", self);
                panic!("Found unknown opcode at instruction: {:#x}, addr: {:#x}", instr, self.pc);
            },
        }

        // Increment the program counter to the next instruction.
        if !ret {
            self.pc += INSTRUCTION_SIZE;
        }

        // By default the execution loop in not broken. True will be returned
        // only by a successful RET instruction is executed.
        ret
    }

    /// Gets the value at a specified register.
    fn get_reg(&mut self, reg: u8) -> u8 {
        match reg {
            0x0 => self.v0,
            0x1 => self.v1,
            0x2 => self.v2,
            0x3 => self.v3,
            0x4 => self.v4,
            0x5 => self.v5,
            0x6 => self.v6,
            0x7 => self.v7,
            0x8 => self.v8,
            0x9 => self.v9,
            0xa => self.va,
            0xb => self.vb,
            0xc => self.vc,
            0xd => self.vd,
            0xe => self.ve,
            0xf => self.vf,
            _ => {
                panic!("Cannot get unknown register: V{:X}", reg);
            }
        }
    }

    /// Sets the value of a general purpose register.
    fn set_reg(&mut self, reg: u8, byte: u8) {
        match reg {
            0x0 => self.v0 = byte,
            0x1 => self.v1 = byte,
            0x2 => self.v2 = byte,
            0x3 => self.v3 = byte,
            0x4 => self.v4 = byte,
            0x5 => self.v5 = byte,
            0x6 => self.v6 = byte,
            0x7 => self.v7 = byte,
            0x8 => self.v8 = byte,
            0x9 => self.v9 = byte,
            0xa => self.va = byte,
            0xb => self.vb = byte,
            0xc => self.vc = byte,
            0xd => self.vd = byte,
            0xe => self.ve = byte,
            0xf => self.vf = byte,
            _ => {
                panic!("Cannot set unknown register: V{:X}", reg);
            }
        }
    }
}
<|endoftext|>