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

use llvm::BasicBlockRef;
use rustc::mir::repr as mir;
use trans::adt;
use trans::base;
use trans::build;
use trans::attributes;
use trans::common::{self, Block};
use trans::debuginfo::DebugLoc;
use trans::type_of;
use trans::type_::Type;

use super::MirContext;
use super::operand::OperandValue::{FatPtr, Immediate, Ref};

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
    pub fn trans_block(&mut self, bb: mir::BasicBlock) {
        debug!("trans_block({:?})", bb);

        let mut bcx = self.bcx(bb);
        let data = self.mir.basic_block_data(bb);

        for statement in &data.statements {
            bcx = self.trans_statement(bcx, statement);
        }

        debug!("trans_block: terminator: {:?}", data.terminator());

        match *data.terminator() {
            mir::Terminator::Goto { target } => {
                build::Br(bcx, self.llblock(target), DebugLoc::None)
            }

            mir::Terminator::If { ref cond, targets: (true_bb, false_bb) } => {
                let cond = self.trans_operand(bcx, cond);
                let lltrue = self.llblock(true_bb);
                let llfalse = self.llblock(false_bb);
                build::CondBr(bcx, cond.immediate(), lltrue, llfalse, DebugLoc::None);
            }

            mir::Terminator::Switch { ref discr, ref adt_def, ref targets } => {
                let adt_ty = bcx.tcx().lookup_item_type(adt_def.did).ty;
                let represented_ty = adt::represent_type(bcx.ccx(), adt_ty);

                let discr_lvalue = self.trans_lvalue(bcx, discr);
                let discr = adt::trans_get_discr(bcx, &represented_ty, discr_lvalue.llval, None);

                // The else branch of the Switch can't be hit, so branch to an unreachable
                // instruction so LLVM knows that
                let unreachable_blk = self.unreachable_block();

                let switch = build::Switch(bcx, discr, unreachable_blk.llbb, targets.len());
                assert_eq!(adt_def.variants.len(), targets.len());
                for (adt_variant, target) in adt_def.variants.iter().zip(targets) {
                    let llval = adt::trans_case(bcx, &*represented_ty, adt_variant.disr_val);
                    let llbb = self.llblock(*target);

                    build::AddCase(switch, llval, llbb)
                }
            }

            mir::Terminator::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
                let (otherwise, targets) = targets.split_last().unwrap();
                let discr = build::Load(bcx, self.trans_lvalue(bcx, discr).llval);
                let switch = build::Switch(bcx, discr, self.llblock(*otherwise), values.len());
                for (value, target) in values.iter().zip(targets) {
                    let llval = self.trans_constval(bcx, value, switch_ty).immediate();
                    let llbb = self.llblock(*target);
                    build::AddCase(switch, llval, llbb)
                }
            }

            mir::Terminator::Resume => {
                if let Some(llpersonalityslot) = self.llpersonalityslot {
                    let lp = build::Load(bcx, llpersonalityslot);
                    // FIXME(lifetime) base::call_lifetime_end(bcx, self.personality);
                    build::Resume(bcx, lp);
                } else {
                    panic!("resume terminator without personality slot")
                }
            }

            mir::Terminator::Return => {
                let return_ty = bcx.monomorphize(&self.mir.return_ty);
                base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None);
            }

            mir::Terminator::Call { ref data, targets } => {
                // The location we'll write the result of the call into.
                let call_dest = self.trans_lvalue(bcx, &data.destination);

                // Create the callee. This will always be a fn
                // ptr and hence a kind of scalar.
                let callee = self.trans_operand(bcx, &data.func);
                let ret_ty = if let ty::TyBareFn(_, ref f) = callee.ty.sty {
                    let sig = bcx.tcx().erase_late_bound_regions(&f.sig);
                    let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
                    sig.output
                } else {
                    panic!("trans_block: expected TyBareFn as callee");
                };

                // The arguments we'll be passing
                let mut llargs = vec![];

                // Does the fn use an outptr? If so, that's the first arg.
                if let ty::FnConverging(ret_ty) = ret_ty {
                    if type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
                        llargs.push(call_dest.llval);
                    }
                }

                // Process the rest of the args.
                for arg in &data.args {
                    let arg_op = self.trans_operand(bcx, arg);
                    match arg_op.val {
                        Ref(llval) | Immediate(llval) => llargs.push(llval),
                        FatPtr(base, extra) => {
                            // The two words in a fat ptr are passed separately
                            llargs.push(base);
                            llargs.push(extra);
                        }
                    }
                }

                // FIXME: Handle panics
                //let panic_bb = self.llblock(targets.1);
                //self.make_landing_pad(panic_bb);

                // Do the actual call.
                let (llret, b) = base::invoke(bcx,
                                              callee.immediate(),
                                              &llargs[..],
                                              callee.ty,
                                              DebugLoc::None);
                bcx = b;

                // Copy the return value into the destination.
                if let ty::FnConverging(ret_ty) = ret_ty {
                    if !type_of::return_uses_outptr(bcx.ccx(), ret_ty) &&
                       !common::type_is_zero_size(bcx.ccx(), ret_ty) {
                        base::store_ty(bcx, llret, call_dest.llval, ret_ty);
                    }
                }

                build::Br(bcx, self.llblock(targets.0), DebugLoc::None)
            },

            mir::Terminator::DivergingCall { .. } => {
                unimplemented!()
            }
        }
    }

    fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
        match self.unreachable_block {
            Some(b) => b,
            None => {
                let bl = self.fcx.new_block(false, "unreachable", None);
                build::Unreachable(bl);
                self.unreachable_block = Some(bl);
                bl
            }
        }
    }

    fn bcx(&self, bb: mir::BasicBlock) -> Block<'bcx, 'tcx> {
        self.blocks[bb.index()]
    }

    fn llblock(&self, bb: mir::BasicBlock) -> BasicBlockRef {
        self.blocks[bb.index()].llbb
    }
}
<commit_msg>Refine call terminator translation<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use llvm::BasicBlockRef;
use rustc::mir::repr as mir;
use trans::adt;
use trans::base;
use trans::build;
use trans::attributes;
use trans::common::{self, Block};
use trans::debuginfo::DebugLoc;
use trans::type_of;
use trans::type_::Type;

use super::MirContext;
use super::operand::OperandValue::{FatPtr, Immediate, Ref};

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
    pub fn trans_block(&mut self, bb: mir::BasicBlock) {
        debug!("trans_block({:?})", bb);

        let mut bcx = self.bcx(bb);
        let data = self.mir.basic_block_data(bb);

        for statement in &data.statements {
            bcx = self.trans_statement(bcx, statement);
        }

        debug!("trans_block: terminator: {:?}", data.terminator());

        match *data.terminator() {
            mir::Terminator::Goto { target } => {
                build::Br(bcx, self.llblock(target), DebugLoc::None)
            }

            mir::Terminator::If { ref cond, targets: (true_bb, false_bb) } => {
                let cond = self.trans_operand(bcx, cond);
                let lltrue = self.llblock(true_bb);
                let llfalse = self.llblock(false_bb);
                build::CondBr(bcx, cond.immediate(), lltrue, llfalse, DebugLoc::None);
            }

            mir::Terminator::Switch { ref discr, ref adt_def, ref targets } => {
                let adt_ty = bcx.tcx().lookup_item_type(adt_def.did).ty;
                let represented_ty = adt::represent_type(bcx.ccx(), adt_ty);

                let discr_lvalue = self.trans_lvalue(bcx, discr);
                let discr = adt::trans_get_discr(bcx, &represented_ty, discr_lvalue.llval, None);

                // The else branch of the Switch can't be hit, so branch to an unreachable
                // instruction so LLVM knows that
                let unreachable_blk = self.unreachable_block();

                let switch = build::Switch(bcx, discr, unreachable_blk.llbb, targets.len());
                assert_eq!(adt_def.variants.len(), targets.len());
                for (adt_variant, target) in adt_def.variants.iter().zip(targets) {
                    let llval = adt::trans_case(bcx, &*represented_ty, adt_variant.disr_val);
                    let llbb = self.llblock(*target);

                    build::AddCase(switch, llval, llbb)
                }
            }

            mir::Terminator::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
                let (otherwise, targets) = targets.split_last().unwrap();
                let discr = build::Load(bcx, self.trans_lvalue(bcx, discr).llval);
                let switch = build::Switch(bcx, discr, self.llblock(*otherwise), values.len());
                for (value, target) in values.iter().zip(targets) {
                    let llval = self.trans_constval(bcx, value, switch_ty).immediate();
                    let llbb = self.llblock(*target);
                    build::AddCase(switch, llval, llbb)
                }
            }

            mir::Terminator::Resume => {
                if let Some(personalityslot) = self.llpersonalityslot {
                    let lp = build::Load(bcx, personalityslot);
                    base::call_lifetime_end(bcx, personalityslot);
                    build::Resume(bcx, lp);
                } else {
                    panic!("resume terminator without personality slot set")
                }
            }

            mir::Terminator::Return => {
                let return_ty = bcx.monomorphize(&self.mir.return_ty);
                base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None);
            }

            mir::Terminator::Call { ref func, ref args, ref destination, ref targets } => {
                // The location we'll write the result of the call into.
                let call_dest = self.trans_lvalue(bcx, destination);
                let ret_ty = call_dest.ty.to_ty(bcx.tcx());
                // Create the callee. This will always be a fn
                // ptr and hence a kind of scalar.
                let callee = self.trans_operand(bcx, func);

                // Does the fn use an outptr? If so, we have an extra first argument.
                let return_outptr = type_of::return_uses_outptr(bcx.ccx(), ret_ty);
                // The arguments we'll be passing.
                let mut llargs = if return_outptr {
                    let mut vec = Vec::with_capacity(args.len() + 1);
                    vec.push(call_dest.llval);
                    vec
                } else {
                    Vec::with_capacity(args.len())
                };

                // Process the rest of the args.
                for arg in args {
                    let arg_op = self.trans_operand(bcx, arg);
                    match arg_op.val {
                        Ref(llval) | Immediate(llval) => llargs.push(llval),
                        FatPtr(base, extra) => {
                            // The two words in a fat ptr are passed separately
                            llargs.push(base);
                            llargs.push(extra);
                        }
                    }
                }

                let debugloc = DebugLoc::None;
                let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty);
                match *targets {
                    mir::CallTargets::Return(ret) => {
                        let llret = build::Call(bcx,
                                                callee.immediate(),
                                                &llargs[..],
                                                Some(attrs),
                                                debugloc);
                        if !return_outptr && !common::type_is_zero_size(bcx.ccx(), ret_ty) {
                            base::store_ty(bcx, llret, call_dest.llval, ret_ty);
                        }
                        build::Br(bcx, self.llblock(ret), debugloc)
                    }
                    mir::CallTargets::WithCleanup((ret, cleanup)) => {
                        let landingpad = self.make_landing_pad(cleanup);
                        build::Invoke(bcx,
                                      callee.immediate(),
                                      &llargs[..],
                                      self.llblock(ret),
                                      landingpad.llbb,
                                      Some(attrs),
                                      debugloc);
                        if !return_outptr && !common::type_is_zero_size(bcx.ccx(), ret_ty) {
                            // FIXME: What do we do here?
                            unimplemented!()
                        }
                    }
                }
            },

            mir::Terminator::DivergingCall { ref func, ref args, ref cleanup } => {
                let callee = self.trans_operand(bcx, func);
                let mut llargs = Vec::with_capacity(args.len());
                for arg in args {
                    match self.trans_operand(bcx, arg).val {
                        Ref(llval) | Immediate(llval) => llargs.push(llval),
                        FatPtr(b, e) => {
                            llargs.push(b);
                            llargs.push(e);
                        }
                    }
                }
                let debugloc = DebugLoc::None;
                let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty);
                match *cleanup {
                    None => {
                        build::Call(bcx, callee.immediate(), &llargs[..], Some(attrs), debugloc);
                        build::Unreachable(bcx);
                    }
                    Some(cleanup) => {
                        let landingpad = self.make_landing_pad(cleanup);
                        let unreachable = self.unreachable_block();
                        build::Invoke(bcx,
                                      callee.immediate(),
                                      &llargs[..],
                                      unreachable.llbb,
                                      landingpad.llbb,
                                      Some(attrs),
                                      debugloc);
                    }
                }
            }
        }
    }

    fn make_landing_pad(&mut self, cleanup: mir::BasicBlock) -> Block<'bcx, 'tcx> {
        let bcx = self.bcx(cleanup).fcx.new_block(true, "cleanup", None);
        let ccx = bcx.ccx();
        let llpersonality = bcx.fcx.eh_personality();
        let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
        let llretval = build::LandingPad(bcx, llretty, llpersonality, 1);
        build::SetCleanup(bcx, llretval);
        match self.llpersonalityslot {
            Some(slot) => build::Store(bcx, llretval, slot),
            None => {
                let personalityslot = base::alloca(bcx, llretty, "personalityslot");
                self.llpersonalityslot = Some(personalityslot);
                base::call_lifetime_start(bcx, personalityslot);
                build::Store(bcx, llretval, personalityslot)
            }
        };
        build::Br(bcx, self.llblock(cleanup), DebugLoc::None);
        bcx
    }

    fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
        match self.unreachable_block {
            Some(b) => b,
            None => {
                let bl = self.fcx.new_block(false, "unreachable", None);
                build::Unreachable(bl);
                self.unreachable_block = Some(bl);
                bl
            }
        }
    }

    fn bcx(&self, bb: mir::BasicBlock) -> Block<'bcx, 'tcx> {
        self.blocks[bb.index()]
    }

    fn llblock(&self, bb: mir::BasicBlock) -> BasicBlockRef {
        self.blocks[bb.index()].llbb
    }
}
<|endoftext|>


<commit_before>use crate::core::{GitReference, PackageId, SourceId};
use crate::sources::git;
use crate::sources::registry::MaybeLock;
use crate::sources::registry::{
    RegistryConfig, RegistryData, CHECKSUM_TEMPLATE, CRATE_TEMPLATE, LOWER_PREFIX_TEMPLATE,
    PREFIX_TEMPLATE, VERSION_TEMPLATE,
};
use crate::util::errors::CargoResult;
use crate::util::interning::InternedString;
use crate::util::{Config, Filesystem};
use anyhow::Context as _;
use cargo_util::{paths, registry::make_dep_path, Sha256};
use lazycell::LazyCell;
use log::{debug, trace};
use std::cell::{Cell, Ref, RefCell};
use std::fmt::Write as FmtWrite;
use std::fs::{self, File, OpenOptions};
use std::io::prelude::*;
use std::io::SeekFrom;
use std::mem;
use std::path::Path;
use std::str;

/// A remote registry is a registry that lives at a remote URL (such as
/// crates.io). The git index is cloned locally, and `.crate` files are
/// downloaded as needed and cached locally.
pub struct RemoteRegistry<'cfg> {
    index_path: Filesystem,
    /// Path to the cache of `.crate` files (`$CARGO_HOME/registry/path/$REG-HASH`).
    cache_path: Filesystem,
    source_id: SourceId,
    index_git_ref: GitReference,
    config: &'cfg Config,
    tree: RefCell<Option<git2::Tree<'static>>>,
    repo: LazyCell<git2::Repository>,
    head: Cell<Option<git2::Oid>>,
    current_sha: Cell<Option<InternedString>>,
}

impl<'cfg> RemoteRegistry<'cfg> {
    pub fn new(source_id: SourceId, config: &'cfg Config, name: &str) -> RemoteRegistry<'cfg> {
        RemoteRegistry {
            index_path: config.registry_index_path().join(name),
            cache_path: config.registry_cache_path().join(name),
            source_id,
            config,
            // TODO: we should probably make this configurable
            index_git_ref: GitReference::DefaultBranch,
            tree: RefCell::new(None),
            repo: LazyCell::new(),
            head: Cell::new(None),
            current_sha: Cell::new(None),
        }
    }

    fn repo(&self) -> CargoResult<&git2::Repository> {
        self.repo.try_borrow_with(|| {
            let path = self.config.assert_package_cache_locked(&self.index_path);

            // Fast path without a lock
            if let Ok(repo) = git2::Repository::open(&path) {
                trace!("opened a repo without a lock");
                return Ok(repo);
            }

            // Ok, now we need to lock and try the whole thing over again.
            trace!("acquiring registry index lock");
            match git2::Repository::open(&path) {
                Ok(repo) => Ok(repo),
                Err(_) => {
                    drop(paths::remove_dir_all(&path));
                    paths::create_dir_all(&path)?;

                    // Note that we'd actually prefer to use a bare repository
                    // here as we're not actually going to check anything out.
                    // All versions of Cargo, though, share the same CARGO_HOME,
                    // so for compatibility with older Cargo which *does* do
                    // checkouts we make sure to initialize a new full
                    // repository (not a bare one).
                    //
                    // We should change this to `init_bare` whenever we feel
                    // like enough time has passed or if we change the directory
                    // that the folder is located in, such as by changing the
                    // hash at the end of the directory.
                    //
                    // Note that in the meantime we also skip `init.templatedir`
                    // as it can be misconfigured sometimes or otherwise add
                    // things that we don't want.
                    let mut opts = git2::RepositoryInitOptions::new();
                    opts.external_template(false);
                    Ok(git2::Repository::init_opts(&path, &opts)
                        .with_context(|| "failed to initialize index git repository")?)
                }
            }
        })
    }

    fn head(&self) -> CargoResult<git2::Oid> {
        if self.head.get().is_none() {
            let repo = self.repo()?;
            let oid = self.index_git_ref.resolve(repo)?;
            self.head.set(Some(oid));
        }
        Ok(self.head.get().unwrap())
    }

    fn tree(&self) -> CargoResult<Ref<'_, git2::Tree<'_>>> {
        {
            let tree = self.tree.borrow();
            if tree.is_some() {
                return Ok(Ref::map(tree, |s| s.as_ref().unwrap()));
            }
        }
        let repo = self.repo()?;
        let commit = repo.find_commit(self.head()?)?;
        let tree = commit.tree()?;

        // Unfortunately in libgit2 the tree objects look like they've got a
        // reference to the repository object which means that a tree cannot
        // outlive the repository that it came from. Here we want to cache this
        // tree, though, so to accomplish this we transmute it to a static
        // lifetime.
        //
        // Note that we don't actually hand out the static lifetime, instead we
        // only return a scoped one from this function. Additionally the repo
        // we loaded from (above) lives as long as this object
        // (`RemoteRegistry`) so we then just need to ensure that the tree is
        // destroyed first in the destructor, hence the destructor on
        // `RemoteRegistry` below.
        let tree = unsafe { mem::transmute::<git2::Tree<'_>, git2::Tree<'static>>(tree) };
        *self.tree.borrow_mut() = Some(tree);
        Ok(Ref::map(self.tree.borrow(), |s| s.as_ref().unwrap()))
    }

    fn filename(&self, pkg: PackageId) -> String {
        format!("{}-{}.crate", pkg.name(), pkg.version())
    }
}

const LAST_UPDATED_FILE: &str = ".last-updated";

impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
    fn prepare(&self) -> CargoResult<()> {
        self.repo()?; // create intermediate dirs and initialize the repo
        Ok(())
    }

    fn index_path(&self) -> &Filesystem {
        &self.index_path
    }

    fn assert_index_locked<'a>(&self, path: &'a Filesystem) -> &'a Path {
        self.config.assert_package_cache_locked(path)
    }

    fn current_version(&self) -> Option<InternedString> {
        if let Some(sha) = self.current_sha.get() {
            return Some(sha);
        }
        let sha = InternedString::new(&self.head().ok()?.to_string());
        self.current_sha.set(Some(sha));
        Some(sha)
    }

    fn load(
        &self,
        _root: &Path,
        path: &Path,
        data: &mut dyn FnMut(&[u8]) -> CargoResult<()>,
    ) -> CargoResult<()> {
        // Note that the index calls this method and the filesystem is locked
        // in the index, so we don't need to worry about an `update_index`
        // happening in a different process.
        let repo = self.repo()?;
        let tree = self.tree()?;
        let entry = tree.get_path(path)?;
        let object = entry.to_object(repo)?;
        let blob = match object.as_blob() {
            Some(blob) => blob,
            None => anyhow::bail!("path `{}` is not a blob in the git repo", path.display()),
        };
        data(blob.content())
    }

    fn config(&mut self) -> CargoResult<Option<RegistryConfig>> {
        debug!("loading config");
        self.prepare()?;
        self.config.assert_package_cache_locked(&self.index_path);
        let mut config = None;
        self.load(Path::new(""), Path::new("config.json"), &mut |json| {
            config = Some(serde_json::from_slice(json)?);
            Ok(())
        })?;
        trace!("config loaded");
        Ok(config)
    }

    fn update_index(&mut self) -> CargoResult<()> {
        if self.config.offline() {
            return Ok(());
        }
        if self.config.cli_unstable().no_index_update {
            return Ok(());
        }
        // Make sure the index is only updated once per session since it is an
        // expensive operation. This generally only happens when the resolver
        // is run multiple times, such as during `cargo publish`.
        if self.config.updated_sources().contains(&self.source_id) {
            return Ok(());
        }

        debug!("updating the index");

        // Ensure that we'll actually be able to acquire an HTTP handle later on
        // once we start trying to download crates. This will weed out any
        // problems with `.cargo/config` configuration related to HTTP.
        //
        // This way if there's a problem the error gets printed before we even
        // hit the index, which may not actually read this configuration.
        self.config.http()?;

        self.prepare()?;
        self.head.set(None);
        *self.tree.borrow_mut() = None;
        self.current_sha.set(None);
        let path = self.config.assert_package_cache_locked(&self.index_path);
        self.config
            .shell()
            .status("Updating", self.source_id.display_index())?;

        // Fetch the latest version of our `index_git_ref` into the index
        // checkout.
        let url = self.source_id.url();
        let repo = self.repo.borrow_mut().unwrap();
        git::fetch(repo, url.as_str(), &self.index_git_ref, self.config)
            .with_context(|| format!("failed to fetch `{}`", url))?;
        self.config.updated_sources().insert(self.source_id);

        // Create a dummy file to record the mtime for when we updated the
        // index.
        paths::create(&path.join(LAST_UPDATED_FILE))?;

        Ok(())
    }

    fn download(&mut self, pkg: PackageId, checksum: &str) -> CargoResult<MaybeLock> {
        let filename = self.filename(pkg);

        // Attempt to open an read-only copy first to avoid an exclusive write
        // lock and also work with read-only filesystems. Note that we check the
        // length of the file like below to handle interrupted downloads.
        //
        // If this fails then we fall through to the exclusive path where we may
        // have to redownload the file.
        let path = self.cache_path.join(&filename);
        let path = self.config.assert_package_cache_locked(&path);
        if let Ok(dst) = File::open(&path) {
            let meta = dst.metadata()?;
            if meta.len() > 0 {
                return Ok(MaybeLock::Ready(dst));
            }
        }

        let config = self.config()?.unwrap();
        let mut url = config.dl;
        if !url.contains(CRATE_TEMPLATE)
            && !url.contains(VERSION_TEMPLATE)
            && !url.contains(PREFIX_TEMPLATE)
            && !url.contains(LOWER_PREFIX_TEMPLATE)
            && !url.contains(CHECKSUM_TEMPLATE)
        {
            write!(url, "/{}/{}/download", CRATE_TEMPLATE, VERSION_TEMPLATE).unwrap();
        }
        let prefix = make_dep_path(&*pkg.name(), true);
        let url = url
            .replace(CRATE_TEMPLATE, &*pkg.name())
            .replace(VERSION_TEMPLATE, &pkg.version().to_string())
            .replace(PREFIX_TEMPLATE, &prefix)
            .replace(LOWER_PREFIX_TEMPLATE, &prefix.to_lowercase())
            .replace(CHECKSUM_TEMPLATE, checksum);

        Ok(MaybeLock::Download {
            url,
            descriptor: pkg.to_string(),
        })
    }

    fn finish_download(
        &mut self,
        pkg: PackageId,
        checksum: &str,
        data: &[u8],
    ) -> CargoResult<File> {
        // Verify what we just downloaded
        let actual = Sha256::new().update(data).finish_hex();
        if actual != checksum {
            anyhow::bail!("failed to verify the checksum of `{}`", pkg)
        }

        let filename = self.filename(pkg);
        self.cache_path.create_dir()?;
        let path = self.cache_path.join(&filename);
        let path = self.config.assert_package_cache_locked(&path);
        let mut dst = OpenOptions::new()
            .create(true)
            .read(true)
            .write(true)
            .open(&path)
            .with_context(|| format!("failed to open `{}`", path.display()))?;
        let meta = dst.metadata()?;
        if meta.len() > 0 {
            return Ok(dst);
        }

        dst.write_all(data)?;
        dst.seek(SeekFrom::Start(0))?;
        Ok(dst)
    }

    fn is_crate_downloaded(&self, pkg: PackageId) -> bool {
        let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
        let path = Path::new(&filename);

        let path = self.cache_path.join(path);
        let path = self.config.assert_package_cache_locked(&path);
        if let Ok(meta) = fs::metadata(path) {
            return meta.len() > 0;
        }
        false
    }
}

impl<'cfg> Drop for RemoteRegistry<'cfg> {
    fn drop(&mut self) {
        // Just be sure to drop this before our other fields
        self.tree.borrow_mut().take();
    }
}
<commit_msg>Auto merge of #9869 - nipunn1313:errmsg, r=alexcrichton<commit_after>use crate::core::{GitReference, PackageId, SourceId};
use crate::sources::git;
use crate::sources::registry::MaybeLock;
use crate::sources::registry::{
    RegistryConfig, RegistryData, CHECKSUM_TEMPLATE, CRATE_TEMPLATE, LOWER_PREFIX_TEMPLATE,
    PREFIX_TEMPLATE, VERSION_TEMPLATE,
};
use crate::util::errors::CargoResult;
use crate::util::interning::InternedString;
use crate::util::{Config, Filesystem};
use anyhow::Context as _;
use cargo_util::{paths, registry::make_dep_path, Sha256};
use lazycell::LazyCell;
use log::{debug, trace};
use std::cell::{Cell, Ref, RefCell};
use std::fmt::Write as FmtWrite;
use std::fs::{self, File, OpenOptions};
use std::io::prelude::*;
use std::io::SeekFrom;
use std::mem;
use std::path::Path;
use std::str;

/// A remote registry is a registry that lives at a remote URL (such as
/// crates.io). The git index is cloned locally, and `.crate` files are
/// downloaded as needed and cached locally.
pub struct RemoteRegistry<'cfg> {
    index_path: Filesystem,
    /// Path to the cache of `.crate` files (`$CARGO_HOME/registry/path/$REG-HASH`).
    cache_path: Filesystem,
    source_id: SourceId,
    index_git_ref: GitReference,
    config: &'cfg Config,
    tree: RefCell<Option<git2::Tree<'static>>>,
    repo: LazyCell<git2::Repository>,
    head: Cell<Option<git2::Oid>>,
    current_sha: Cell<Option<InternedString>>,
}

impl<'cfg> RemoteRegistry<'cfg> {
    pub fn new(source_id: SourceId, config: &'cfg Config, name: &str) -> RemoteRegistry<'cfg> {
        RemoteRegistry {
            index_path: config.registry_index_path().join(name),
            cache_path: config.registry_cache_path().join(name),
            source_id,
            config,
            // TODO: we should probably make this configurable
            index_git_ref: GitReference::DefaultBranch,
            tree: RefCell::new(None),
            repo: LazyCell::new(),
            head: Cell::new(None),
            current_sha: Cell::new(None),
        }
    }

    fn repo(&self) -> CargoResult<&git2::Repository> {
        self.repo.try_borrow_with(|| {
            let path = self.config.assert_package_cache_locked(&self.index_path);

            // Fast path without a lock
            if let Ok(repo) = git2::Repository::open(&path) {
                trace!("opened a repo without a lock");
                return Ok(repo);
            }

            // Ok, now we need to lock and try the whole thing over again.
            trace!("acquiring registry index lock");
            match git2::Repository::open(&path) {
                Ok(repo) => Ok(repo),
                Err(_) => {
                    drop(paths::remove_dir_all(&path));
                    paths::create_dir_all(&path)?;

                    // Note that we'd actually prefer to use a bare repository
                    // here as we're not actually going to check anything out.
                    // All versions of Cargo, though, share the same CARGO_HOME,
                    // so for compatibility with older Cargo which *does* do
                    // checkouts we make sure to initialize a new full
                    // repository (not a bare one).
                    //
                    // We should change this to `init_bare` whenever we feel
                    // like enough time has passed or if we change the directory
                    // that the folder is located in, such as by changing the
                    // hash at the end of the directory.
                    //
                    // Note that in the meantime we also skip `init.templatedir`
                    // as it can be misconfigured sometimes or otherwise add
                    // things that we don't want.
                    let mut opts = git2::RepositoryInitOptions::new();
                    opts.external_template(false);
                    Ok(git2::Repository::init_opts(&path, &opts).with_context(|| {
                        format!("failed to initialize index git repository (in {:?})", path)
                    })?)
                }
            }
        })
    }

    fn head(&self) -> CargoResult<git2::Oid> {
        if self.head.get().is_none() {
            let repo = self.repo()?;
            let oid = self.index_git_ref.resolve(repo)?;
            self.head.set(Some(oid));
        }
        Ok(self.head.get().unwrap())
    }

    fn tree(&self) -> CargoResult<Ref<'_, git2::Tree<'_>>> {
        {
            let tree = self.tree.borrow();
            if tree.is_some() {
                return Ok(Ref::map(tree, |s| s.as_ref().unwrap()));
            }
        }
        let repo = self.repo()?;
        let commit = repo.find_commit(self.head()?)?;
        let tree = commit.tree()?;

        // Unfortunately in libgit2 the tree objects look like they've got a
        // reference to the repository object which means that a tree cannot
        // outlive the repository that it came from. Here we want to cache this
        // tree, though, so to accomplish this we transmute it to a static
        // lifetime.
        //
        // Note that we don't actually hand out the static lifetime, instead we
        // only return a scoped one from this function. Additionally the repo
        // we loaded from (above) lives as long as this object
        // (`RemoteRegistry`) so we then just need to ensure that the tree is
        // destroyed first in the destructor, hence the destructor on
        // `RemoteRegistry` below.
        let tree = unsafe { mem::transmute::<git2::Tree<'_>, git2::Tree<'static>>(tree) };
        *self.tree.borrow_mut() = Some(tree);
        Ok(Ref::map(self.tree.borrow(), |s| s.as_ref().unwrap()))
    }

    fn filename(&self, pkg: PackageId) -> String {
        format!("{}-{}.crate", pkg.name(), pkg.version())
    }
}

const LAST_UPDATED_FILE: &str = ".last-updated";

impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
    fn prepare(&self) -> CargoResult<()> {
        self.repo()?; // create intermediate dirs and initialize the repo
        Ok(())
    }

    fn index_path(&self) -> &Filesystem {
        &self.index_path
    }

    fn assert_index_locked<'a>(&self, path: &'a Filesystem) -> &'a Path {
        self.config.assert_package_cache_locked(path)
    }

    fn current_version(&self) -> Option<InternedString> {
        if let Some(sha) = self.current_sha.get() {
            return Some(sha);
        }
        let sha = InternedString::new(&self.head().ok()?.to_string());
        self.current_sha.set(Some(sha));
        Some(sha)
    }

    fn load(
        &self,
        _root: &Path,
        path: &Path,
        data: &mut dyn FnMut(&[u8]) -> CargoResult<()>,
    ) -> CargoResult<()> {
        // Note that the index calls this method and the filesystem is locked
        // in the index, so we don't need to worry about an `update_index`
        // happening in a different process.
        let repo = self.repo()?;
        let tree = self.tree()?;
        let entry = tree.get_path(path)?;
        let object = entry.to_object(repo)?;
        let blob = match object.as_blob() {
            Some(blob) => blob,
            None => anyhow::bail!("path `{}` is not a blob in the git repo", path.display()),
        };
        data(blob.content())
    }

    fn config(&mut self) -> CargoResult<Option<RegistryConfig>> {
        debug!("loading config");
        self.prepare()?;
        self.config.assert_package_cache_locked(&self.index_path);
        let mut config = None;
        self.load(Path::new(""), Path::new("config.json"), &mut |json| {
            config = Some(serde_json::from_slice(json)?);
            Ok(())
        })?;
        trace!("config loaded");
        Ok(config)
    }

    fn update_index(&mut self) -> CargoResult<()> {
        if self.config.offline() {
            return Ok(());
        }
        if self.config.cli_unstable().no_index_update {
            return Ok(());
        }
        // Make sure the index is only updated once per session since it is an
        // expensive operation. This generally only happens when the resolver
        // is run multiple times, such as during `cargo publish`.
        if self.config.updated_sources().contains(&self.source_id) {
            return Ok(());
        }

        debug!("updating the index");

        // Ensure that we'll actually be able to acquire an HTTP handle later on
        // once we start trying to download crates. This will weed out any
        // problems with `.cargo/config` configuration related to HTTP.
        //
        // This way if there's a problem the error gets printed before we even
        // hit the index, which may not actually read this configuration.
        self.config.http()?;

        self.prepare()?;
        self.head.set(None);
        *self.tree.borrow_mut() = None;
        self.current_sha.set(None);
        let path = self.config.assert_package_cache_locked(&self.index_path);
        self.config
            .shell()
            .status("Updating", self.source_id.display_index())?;

        // Fetch the latest version of our `index_git_ref` into the index
        // checkout.
        let url = self.source_id.url();
        let repo = self.repo.borrow_mut().unwrap();
        git::fetch(repo, url.as_str(), &self.index_git_ref, self.config)
            .with_context(|| format!("failed to fetch `{}`", url))?;
        self.config.updated_sources().insert(self.source_id);

        // Create a dummy file to record the mtime for when we updated the
        // index.
        paths::create(&path.join(LAST_UPDATED_FILE))?;

        Ok(())
    }

    fn download(&mut self, pkg: PackageId, checksum: &str) -> CargoResult<MaybeLock> {
        let filename = self.filename(pkg);

        // Attempt to open an read-only copy first to avoid an exclusive write
        // lock and also work with read-only filesystems. Note that we check the
        // length of the file like below to handle interrupted downloads.
        //
        // If this fails then we fall through to the exclusive path where we may
        // have to redownload the file.
        let path = self.cache_path.join(&filename);
        let path = self.config.assert_package_cache_locked(&path);
        if let Ok(dst) = File::open(&path) {
            let meta = dst.metadata()?;
            if meta.len() > 0 {
                return Ok(MaybeLock::Ready(dst));
            }
        }

        let config = self.config()?.unwrap();
        let mut url = config.dl;
        if !url.contains(CRATE_TEMPLATE)
            && !url.contains(VERSION_TEMPLATE)
            && !url.contains(PREFIX_TEMPLATE)
            && !url.contains(LOWER_PREFIX_TEMPLATE)
            && !url.contains(CHECKSUM_TEMPLATE)
        {
            write!(url, "/{}/{}/download", CRATE_TEMPLATE, VERSION_TEMPLATE).unwrap();
        }
        let prefix = make_dep_path(&*pkg.name(), true);
        let url = url
            .replace(CRATE_TEMPLATE, &*pkg.name())
            .replace(VERSION_TEMPLATE, &pkg.version().to_string())
            .replace(PREFIX_TEMPLATE, &prefix)
            .replace(LOWER_PREFIX_TEMPLATE, &prefix.to_lowercase())
            .replace(CHECKSUM_TEMPLATE, checksum);

        Ok(MaybeLock::Download {
            url,
            descriptor: pkg.to_string(),
        })
    }

    fn finish_download(
        &mut self,
        pkg: PackageId,
        checksum: &str,
        data: &[u8],
    ) -> CargoResult<File> {
        // Verify what we just downloaded
        let actual = Sha256::new().update(data).finish_hex();
        if actual != checksum {
            anyhow::bail!("failed to verify the checksum of `{}`", pkg)
        }

        let filename = self.filename(pkg);
        self.cache_path.create_dir()?;
        let path = self.cache_path.join(&filename);
        let path = self.config.assert_package_cache_locked(&path);
        let mut dst = OpenOptions::new()
            .create(true)
            .read(true)
            .write(true)
            .open(&path)
            .with_context(|| format!("failed to open `{}`", path.display()))?;
        let meta = dst.metadata()?;
        if meta.len() > 0 {
            return Ok(dst);
        }

        dst.write_all(data)?;
        dst.seek(SeekFrom::Start(0))?;
        Ok(dst)
    }

    fn is_crate_downloaded(&self, pkg: PackageId) -> bool {
        let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
        let path = Path::new(&filename);

        let path = self.cache_path.join(path);
        let path = self.config.assert_package_cache_locked(&path);
        if let Ok(meta) = fs::metadata(path) {
            return meta.len() > 0;
        }
        false
    }
}

impl<'cfg> Drop for RemoteRegistry<'cfg> {
    fn drop(&mut self) {
        // Just be sure to drop this before our other fields
        self.tree.borrow_mut().take();
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/minimum-length-of-string-after-deleting-similar-ends/
pub fn minimum_length(s: String) -> i32 {
    let bytes = s.as_bytes();
    let mut i = 0;
    let mut j = bytes.len() - 1;
    while i <= j && bytes[i] == bytes[j] {
        let tmp = bytes[i];
        while i <= j && bytes[i] == bytes[j] {
            i += 1;
        }
        while i <= j && tmp == bytes[j] {
            j -= 1;
        }
    }
    let answer = (j as i32 - i as i32) + 1;
    answer
}

fn main() {
    println!("{}", minimum_length("ca".to_string())); // 2
    println!("{}", minimum_length("cabaabac".to_string())); // 0
    println!("{}", minimum_length("aabccabba".to_string())); // 3
    println!(
        "{}",
        minimum_length("bbbbbbbbbbbbbbbbbbbbbbbbbbbabbbbbbbbbbbbbbbccbcbcbccbbabbb".to_string())
    ); // 1
}
<commit_msg>Solve problem 1750<commit_after>// https://leetcode.com/problems/minimum-length-of-string-after-deleting-similar-ends/
pub fn minimum_length(s: String) -> i32 {
    let bytes = s.as_bytes();
    let mut i = 0;
    let mut j = bytes.len() - 1;
    while i < j && bytes[i] == bytes[j] {
        let tmp = bytes[i];
        while i <= j && bytes[i] == bytes[j] {
            i += 1;
        }
        while i < j && tmp == bytes[j] {
            j -= 1;
        }
    }
    let answer = (j as i32 - i as i32) + 1;
    answer
}

fn main() {
    println!("{}", minimum_length("ca".to_string())); // 2
    println!("{}", minimum_length("cabaabac".to_string())); // 0
    println!("{}", minimum_length("aabccabba".to_string())); // 3
    println!(
        "{}",
        minimum_length("bbbbbbbbbbbbbbbbbbbbbbbbbbbabbbbbbbbbbbbbbbccbcbcbccbbabbb".to_string())
    ); // 1
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/number-of-pairs-of-interchangeable-rectangles/
pub fn interchangeable_rectangles(rectangles: Vec<Vec<i32>>) -> i64 {
    todo!()
}

fn main() {
    println!(
        "{}",
        interchangeable_rectangles(vec![vec![4, 8], vec![3, 6], vec![10, 20], vec![15, 30]])
    ); // 6
    println!(
        "{}",
        interchangeable_rectangles(vec![vec![4, 5], vec![7, 8]])
    ); // 0
}
<commit_msg>Solve problem 2001<commit_after>use std::collections::HashMap;

// https://leetcode.com/problems/number-of-pairs-of-interchangeable-rectangles/
pub fn interchangeable_rectangles(rectangles: Vec<Vec<i32>>) -> i64 {
    fn gcd(a: i32, b: i32) -> i32 {
        if a == b {
            return a;
        }
        if a > b {
            return gcd(a - b, b);
        }
        gcd(a, b - a)
    }

    fn series(n: i32, a: i32, b: i32) -> i64 {
        ((n as f64 / 2.0) * (a + b) as f64) as i64
    }

    let mut answer: i64 = 0;
    let mut map: HashMap<String, i32> = HashMap::new();
    for rectangle in rectangles.into_iter() {
        let gcd = gcd(rectangle[0], rectangle[1]);
        let s = format!("{}/{}", rectangle[0] / gcd, rectangle[1] / gcd);
        let count = map.get(&s).unwrap_or(&0) + 1;
        map.insert(s, count);
    }
    answer += map
        .into_iter()
        .map(|a| series(a.1 - 1, 1, a.1 - 1))
        .sum::<i64>();
    answer
}

fn main() {
    println!(
        "{}",
        interchangeable_rectangles(vec![vec![4, 8], vec![3, 6], vec![10, 20], vec![15, 30]])
    ); // 6
    println!(
        "{}",
        interchangeable_rectangles(vec![vec![4, 5], vec![7, 8]])
    ); // 0
    println!(
        "{}",
        interchangeable_rectangles(vec![vec![3, 4], vec![6, 8], vec![9, 12]])
    ); // 3
    println!(
        "{}",
        interchangeable_rectangles(vec![
            vec![4, 8],
            vec![3, 6],
            vec![10, 20],
            vec![15, 30],
            vec![3, 4],
            vec![6, 8],
            vec![9, 12]
        ])
    ); // 9
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/longest-nice-subarray/
pub fn longest_nice_subarray(nums: Vec<i32>) -> i32 {
    todo!()
}

fn main() {
    println!("{}", longest_nice_subarray(vec![1, 3, 8, 48, 10])); // 3
    println!("{}", longest_nice_subarray(vec![3, 1, 5, 11, 13])); // 1
}
<commit_msg>Solve problem 2401<commit_after>// https://leetcode.com/problems/longest-nice-subarray/
pub fn longest_nice_subarray(nums: Vec<i32>) -> i32 {
    let mut answer = 0i32;
    let mut j = 0;
    let mut i = 0;
    let mut mask = 0;
    while i < nums.len() {
        while mask & nums[i] != 0 {
            mask ^= nums[j];
            j += 1;
        }
        mask = mask | nums[i];
        i += 1;
        answer = answer.max((i - j) as i32);
    }
    answer
}

fn main() {
    println!("{}", longest_nice_subarray(vec![1, 3, 8, 48, 10])); // 3
    println!("{}", longest_nice_subarray(vec![3, 1, 5, 11, 13])); // 1
}
<|endoftext|>


<commit_before>use std::ops::Range;
use std::collections::HashSet;

use rand;
use rand::Rng;

use tcod::console::Console;
use tcod::Color;
use tcod::colors;

use traits::{Position, Renderable};
use units::Unit;
use {SCREEN_HEIGHT, SCREEN_WIDTH, PANEL_HEIGHT};

use point::Point;
use rectangle::Rectangle;

const MAP_WIDTH: i8 = SCREEN_WIDTH;
const MAP_HEIGHT: i8 = SCREEN_HEIGHT - PANEL_HEIGHT;

const ROOM_MAX_SIZE: u8 = 10;
const ROOM_MIN_SIZE: u8 = 6;
const ROOM_MAX_COUNT: u8 = 30;

const ERR_MSG_TUNNEL: &str = "Failed to create tunnel.";
const ERR_MSG_ROOM: &str = "Failed to create room.";
const ERR_MSG_ROOM_CMP: &str = "Error comparing rooms.";

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TileType {
    Floor,
    Wall,
}

impl TileType {
    fn get_color(self) -> Color {
        match self {
            TileType::Floor => Color::new(50, 50, 150),
            TileType::Wall => Color::new(240, 240, 240),
        }
    }

    fn get_glyph(self) -> char {
        match self {
            TileType::Floor => '.',
            TileType::Wall => '#',
        }
    }

    pub fn blocks_move(self) -> bool {
        match self {
            TileType::Floor => false,
            TileType::Wall => true,
        }
    }

    pub fn blocks_sight(self) -> bool {
        match self {
            TileType::Floor => false,
            TileType::Wall => true,
        }
    }
}

#[derive(Debug)]
pub struct Tile {
    position: Point<i8>,
    tile_type: TileType,
}

impl Position for Tile {
    fn get_x(&self) -> i8 {
        self.position.x
    }

    fn get_y(&self) -> i8 {
        self.position.y
    }
}

impl Renderable for Tile {
    fn get_color(&self) -> Color {
        self.tile_type.get_color()
    }
    fn get_glyph(&self) -> char {
        self.tile_type.get_glyph()
    }
}

impl Tile {
    pub fn new(pos: Point<i8>, tile_type: TileType) -> Tile {
        Tile{
            position: pos,
            tile_type: tile_type
        }
    }
}

#[derive(Debug)]
pub struct Map {
    tile_map: Vec<Tile>,
    npcs: Vec<Unit>,
}

impl Map {
    pub fn init() -> (Map, Point<i8>) {
        let mut map = vec![];
        for y in 0..MAP_HEIGHT {
            for x in 0..MAP_WIDTH {
                map.push( Tile::new(Point{x: x, y: y}, TileType::Wall) );
            }
        }

        let mut map = Map {
            tile_map: map,
            npcs: vec![Unit::new(Point{x: 52, y: 18}, '@', colors::YELLOW)],
        };

        let mut rng = rand::thread_rng();
        let (rooms, player_start) = map.build_rooms(&mut rng);
        map.build_coridoors(&rooms, &mut rng);

        (map, player_start)
    }

    fn build_rooms(&mut self, rng: &mut rand::ThreadRng) -> (Vec<Rectangle>, Point<i8>) {
        let mut rooms = vec![];
        let mut player_start = Point{x:0, y:0};

        for _ in 0..ROOM_MAX_COUNT {
            let width = rng.gen_range(ROOM_MIN_SIZE, ROOM_MAX_SIZE);
            let height = rng.gen_range(ROOM_MIN_SIZE, ROOM_MAX_SIZE);

            let room = Rectangle::new(
                Point {
                    x: rng.gen_range(0, MAP_WIDTH - width as i8 - 1),
                    y: rng.gen_range(0, MAP_HEIGHT - height as i8 - 1)
                },
                (width, height)
            );

            if !rooms.iter().any(|r: &Rectangle| r.is_intersecting(&room)) {
                self.create_room(&room).expect(ERR_MSG_ROOM);

                if rooms.len() == 0 {
                    player_start = room.centre();
                }

                rooms.push(room);
            }
        }

        (rooms, player_start)
    }

    fn build_coridoors(&mut self, rooms: &Vec<Rectangle>, rng: &mut rand::ThreadRng) {
        let mut sorted_rooms: Vec<_> = rooms.iter().map(|r| r).collect();
        let mut connected_rooms = HashSet::new();

        for room in rooms {
            sorted_rooms.sort_by(|a,b| (room.centre() - a.centre()).sqr_radius().partial_cmp(&(room.centre() - b.centre()).sqr_radius()).expect(ERR_MSG_ROOM_CMP) );

            for next in sorted_rooms.iter().skip(1).take(2) {
                if connected_rooms.contains(&(*next, room)) {
                    continue;
                }

                connected_rooms.insert((room, *next));

                let r1_centre = room.centre();
                let r2_centre = next.centre();

                // Decide whether to first tunnel horizontally or vertically.
                if rng.gen_weighted_bool(2) {
                    // Horizontal
                    self.create_h_tunnel(r1_centre.x..r2_centre.x, r1_centre.y).expect(ERR_MSG_TUNNEL);
                    self.create_v_tunnel(r2_centre.x, r1_centre.y..r2_centre.y).expect(ERR_MSG_TUNNEL);
                } else {
                    // Vertical
                    self.create_v_tunnel(r1_centre.x, r1_centre.y..r2_centre.y).expect(ERR_MSG_TUNNEL);
                    self.create_h_tunnel(r1_centre.x..r2_centre.x, r2_centre.y).expect(ERR_MSG_TUNNEL);
                }
            }
        }
    }

    pub fn render_map<T: Console>(&self, cons: &mut T) {
        for tile in self.tile_map.iter() {
            tile.render(cons);
        }
    }

    pub fn render_npcs<T: Console>(&self, cons: &mut T) {
        for unit in self.npcs.iter() {
            unit.render(cons);
        }
    }

    pub fn point_in_map(&self, Point{x,y}: Point<i8>) -> bool {
        x >= 0 && x < MAP_WIDTH && y >= 0 && y < MAP_HEIGHT
    }

    pub fn get_tile_type(&self, pos: Point<i8>) -> Result<TileType,()> {
        if !self.point_in_map(pos) {
            Err(())
        } else {
            let Point{x, y} = pos;
            Ok(self.tile_map[y as usize * MAP_WIDTH as usize + x as usize].tile_type)
        }
    }

    fn create_v_tunnel(&mut self, x: i8, y_r: Range<i8>) -> Result<(),()> {
        // Need to handle the case where start > end.
        // I decided to do it here to make it easier to call the function.
        // Because this is a half-open range, we need to adjust the start
        // and end to account for that.
        let y_r = if y_r.start > y_r.end {
            y_r.end+1 .. y_r.start+1
        } else {
            y_r
        };

        for y in y_r {
            let pos = Point{x:x, y:y};
            self.set_tile_type(pos, TileType::Floor)?;
        }

        Ok(())
    }

    fn create_h_tunnel(&mut self, x_r: Range<i8>, y: i8) -> Result<(),()> {
        // Need to handle the case where start > end.
        // I decided to do it here to make it easier to call the function.
        // Because this is a half-open range, we need to adjust the start
        // and end to account for that.
        let x_r = if x_r.start > x_r.end {
            x_r.end+1 .. x_r.start+1
        } else {
            x_r
        };

        for x in x_r {
            let pos = Point{x:x, y:y};
            self.set_tile_type(pos, TileType::Floor)?;
        }

        Ok(())
    }

    fn create_room(&mut self, rect: &Rectangle) -> Result<(),()> {
        for y in (rect.top_left.y+1)..rect.bottom_right.y {
            for x in (rect.top_left.x+1)..rect.bottom_right.x {
                let pos = Point{x:x, y:y};
                self.set_tile_type(pos, TileType::Floor)?;
            }
        }

        Ok(())
    }

    fn set_tile_type(&mut self, pos: Point<i8>, new_tile: TileType) -> Result<(),()> {
        if !self.point_in_map(pos) {
            Err(())
        } else {
            let Point{x,y} = pos;
            self.tile_map[y as usize * MAP_WIDTH as usize + x as usize].tile_type = new_tile;

            Ok(())
        }
    }
}<commit_msg>Changed corridor generation to use closest 3.<commit_after>use std::ops::Range;
use std::collections::HashSet;

use rand;
use rand::Rng;

use tcod::console::Console;
use tcod::Color;
use tcod::colors;

use traits::{Position, Renderable};
use units::Unit;
use {SCREEN_HEIGHT, SCREEN_WIDTH, PANEL_HEIGHT};

use point::Point;
use rectangle::Rectangle;

const MAP_WIDTH: i8 = SCREEN_WIDTH;
const MAP_HEIGHT: i8 = SCREEN_HEIGHT - PANEL_HEIGHT;

const ROOM_MAX_SIZE: u8 = 10;
const ROOM_MIN_SIZE: u8 = 6;
const ROOM_MAX_COUNT: u8 = 30;

const ERR_MSG_TUNNEL: &str = "Failed to create tunnel.";
const ERR_MSG_ROOM: &str = "Failed to create room.";
const ERR_MSG_ROOM_CMP: &str = "Error comparing rooms.";

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TileType {
    Floor,
    Wall,
}

impl TileType {
    fn get_color(self) -> Color {
        match self {
            TileType::Floor => Color::new(50, 50, 150),
            TileType::Wall => Color::new(240, 240, 240),
        }
    }

    fn get_glyph(self) -> char {
        match self {
            TileType::Floor => '.',
            TileType::Wall => '#',
        }
    }

    pub fn blocks_move(self) -> bool {
        match self {
            TileType::Floor => false,
            TileType::Wall => true,
        }
    }

    pub fn blocks_sight(self) -> bool {
        match self {
            TileType::Floor => false,
            TileType::Wall => true,
        }
    }
}

#[derive(Debug)]
pub struct Tile {
    position: Point<i8>,
    tile_type: TileType,
}

impl Position for Tile {
    fn get_x(&self) -> i8 {
        self.position.x
    }

    fn get_y(&self) -> i8 {
        self.position.y
    }
}

impl Renderable for Tile {
    fn get_color(&self) -> Color {
        self.tile_type.get_color()
    }
    fn get_glyph(&self) -> char {
        self.tile_type.get_glyph()
    }
}

impl Tile {
    pub fn new(pos: Point<i8>, tile_type: TileType) -> Tile {
        Tile{
            position: pos,
            tile_type: tile_type
        }
    }
}

#[derive(Debug)]
pub struct Map {
    tile_map: Vec<Tile>,
    npcs: Vec<Unit>,
}

impl Map {
    pub fn init() -> (Map, Point<i8>) {
        let mut map = vec![];
        for y in 0..MAP_HEIGHT {
            for x in 0..MAP_WIDTH {
                map.push( Tile::new(Point{x: x, y: y}, TileType::Wall) );
            }
        }

        let mut map = Map {
            tile_map: map,
            npcs: vec![Unit::new(Point{x: 52, y: 18}, '@', colors::YELLOW)],
        };

        let mut rng = rand::thread_rng();
        let (rooms, player_start) = map.build_rooms(&mut rng);
        map.build_coridoors(&rooms, &mut rng);

        (map, player_start)
    }

    fn build_rooms(&mut self, rng: &mut rand::ThreadRng) -> (Vec<Rectangle>, Point<i8>) {
        let mut rooms = vec![];
        let mut player_start = Point{x:0, y:0};

        for _ in 0..ROOM_MAX_COUNT {
            let width = rng.gen_range(ROOM_MIN_SIZE, ROOM_MAX_SIZE);
            let height = rng.gen_range(ROOM_MIN_SIZE, ROOM_MAX_SIZE);

            let room = Rectangle::new(
                Point {
                    x: rng.gen_range(0, MAP_WIDTH - width as i8 - 1),
                    y: rng.gen_range(0, MAP_HEIGHT - height as i8 - 1)
                },
                (width, height)
            );

            if !rooms.iter().any(|r: &Rectangle| r.is_intersecting(&room)) {
                self.create_room(&room).expect(ERR_MSG_ROOM);

                if rooms.len() == 0 {
                    player_start = room.centre();
                }

                rooms.push(room);
            }
        }

        (rooms, player_start)
    }

    fn build_coridoors(&mut self, rooms: &Vec<Rectangle>, rng: &mut rand::ThreadRng) {
        let mut sorted_rooms: Vec<_> = rooms.iter().map(|r| r).collect();
        let mut connected_rooms = HashSet::new();

        for room in rooms {
            sorted_rooms.sort_by(|a,b| (room.centre() - a.centre()).sqr_radius().partial_cmp(&(room.centre() - b.centre()).sqr_radius()).expect(ERR_MSG_ROOM_CMP) );

            for next in sorted_rooms.iter().skip(1).take(3) {
                if connected_rooms.contains(&(*next, room)) {
                    continue;
                }

                connected_rooms.insert((room, *next));

                let r1_centre = room.centre();
                let r2_centre = next.centre();

                // Decide whether to first tunnel horizontally or vertically.
                if rng.gen_weighted_bool(2) {
                    // Horizontal
                    self.create_h_tunnel(r1_centre.x..r2_centre.x, r1_centre.y).expect(ERR_MSG_TUNNEL);
                    self.create_v_tunnel(r2_centre.x, r1_centre.y..r2_centre.y).expect(ERR_MSG_TUNNEL);
                } else {
                    // Vertical
                    self.create_v_tunnel(r1_centre.x, r1_centre.y..r2_centre.y).expect(ERR_MSG_TUNNEL);
                    self.create_h_tunnel(r1_centre.x..r2_centre.x, r2_centre.y).expect(ERR_MSG_TUNNEL);
                }
            }
        }
    }

    pub fn render_map<T: Console>(&self, cons: &mut T) {
        for tile in self.tile_map.iter() {
            tile.render(cons);
        }
    }

    pub fn render_npcs<T: Console>(&self, cons: &mut T) {
        for unit in self.npcs.iter() {
            unit.render(cons);
        }
    }

    pub fn point_in_map(&self, Point{x,y}: Point<i8>) -> bool {
        x >= 0 && x < MAP_WIDTH && y >= 0 && y < MAP_HEIGHT
    }

    pub fn get_tile_type(&self, pos: Point<i8>) -> Result<TileType,()> {
        if !self.point_in_map(pos) {
            Err(())
        } else {
            let Point{x, y} = pos;
            Ok(self.tile_map[y as usize * MAP_WIDTH as usize + x as usize].tile_type)
        }
    }

    fn create_v_tunnel(&mut self, x: i8, y_r: Range<i8>) -> Result<(),()> {
        // Need to handle the case where start > end.
        // I decided to do it here to make it easier to call the function.
        // Because this is a half-open range, we need to adjust the start
        // and end to account for that.
        let y_r = if y_r.start > y_r.end {
            y_r.end+1 .. y_r.start+1
        } else {
            y_r
        };

        for y in y_r {
            let pos = Point{x:x, y:y};
            self.set_tile_type(pos, TileType::Floor)?;
        }

        Ok(())
    }

    fn create_h_tunnel(&mut self, x_r: Range<i8>, y: i8) -> Result<(),()> {
        // Need to handle the case where start > end.
        // I decided to do it here to make it easier to call the function.
        // Because this is a half-open range, we need to adjust the start
        // and end to account for that.
        let x_r = if x_r.start > x_r.end {
            x_r.end+1 .. x_r.start+1
        } else {
            x_r
        };

        for x in x_r {
            let pos = Point{x:x, y:y};
            self.set_tile_type(pos, TileType::Floor)?;
        }

        Ok(())
    }

    fn create_room(&mut self, rect: &Rectangle) -> Result<(),()> {
        for y in (rect.top_left.y+1)..rect.bottom_right.y {
            for x in (rect.top_left.x+1)..rect.bottom_right.x {
                let pos = Point{x:x, y:y};
                self.set_tile_type(pos, TileType::Floor)?;
            }
        }

        Ok(())
    }

    fn set_tile_type(&mut self, pos: Point<i8>, new_tile: TileType) -> Result<(),()> {
        if !self.point_in_map(pos) {
            Err(())
        } else {
            let Point{x,y} = pos;
            self.tile_map[y as usize * MAP_WIDTH as usize + x as usize].tile_type = new_tile;

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


<commit_before>use std::num::{One, Zero};
use std::rand::{Rand, Rng, RngUtil};
use std::cmp::ApproxEq;
use traits::rlmul::{RMul, LMul};
use traits::cross::Cross;
use traits::dim::Dim;
use traits::inv::Inv;
use traits::transpose::Transpose;
use traits::rotation::{Rotation, Rotate};
use traits::transformation::{Transform}; // FIXME: implement Transformation and Transformable
use traits::homogeneous::ToHomogeneous;
use traits::indexable::Indexable;
use traits::vector::AlgebraicVec;
use vec::Vec1;
use mat::{Mat2, Mat3};
use vec::Vec3;

/// Matrix wrapper representing rotation matrix. It is built uppon another matrix and ensures (at
/// the type-level) that it will always represent a rotation. Rotation matrices have some
/// properties useful for performances, like the fact that the inversion is simply a transposition.
#[deriving(Eq, ToStr, Clone)]
pub struct Rotmat<M> {
    priv submat: M
}

impl<M: Clone> Rotmat<M> {
    /// Gets a copy of the internal representation of the rotation.
    pub fn submat(&self) -> M {
        self.submat.clone()
    }
}

impl<N: Clone + Trigonometric + Neg<N>> Rotmat<Mat2<N>> {
    /// Builds a 2 dimensional rotation matrix from an angle in radian.
    pub fn from_angle(angle: N) -> Rotmat<Mat2<N>> {
        let (sia, coa) = angle.sin_cos();

        Rotmat {
            submat: Mat2::new(coa.clone(), -sia, sia.clone(), coa)
        }
    }
}

impl<N: Clone + Trigonometric + Num + Algebraic> Rotmat<Mat3<N>> {
    /// Builds a 3 dimensional rotation matrix from an axis and an angle.
    ///
    /// # Arguments
    ///   * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation
    ///   in radian. Its direction is the axis of rotation.
    pub fn from_axis_angle(axisangle: Vec3<N>) -> Rotmat<Mat3<N>> {
        if axisangle.sqnorm().is_zero() {
            One::one()
        }
        else {
            let mut axis   = axisangle;
            let angle      = axis.normalize();
            let _1: N      = One::one();
            let ux         = axis.x.clone();
            let uy         = axis.y.clone();
            let uz         = axis.z.clone();
            let sqx        = ux * ux;
            let sqy        = uy * uy;
            let sqz        = uz * uz;
            let (sin, cos) = angle.sin_cos();
            let one_m_cos  = _1 - cos;

            Rotmat {
                submat: Mat3::new(
                            (sqx + (_1 - sqx) * cos),
                            (ux * uy * one_m_cos - uz * sin),
                            (ux * uz * one_m_cos + uy * sin),

                            (ux * uy * one_m_cos + uz * sin),
                            (sqy + (_1 - sqy) * cos),
                            (uy * uz * one_m_cos - ux * sin),

                            (ux * uz * one_m_cos - uy * sin),
                            (uy * uz * one_m_cos + ux * sin),
                            (sqz + (_1 - sqz) * cos))
            }
        }
    }
}

impl<N: Clone + Num + Algebraic> Rotmat<Mat3<N>> {
    /// Reorient this matrix such that its local `x` axis points to a given point. Note that the
    /// usually known `look_at` function does the same thing but with the `z` axis. See `look_at_z`
    /// for that.
    ///
    /// # Arguments
    ///   * at - The point to look at. It is also the direction the matrix `x` axis will be aligned
    ///   with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at(&mut self, at: &Vec3<N>, up: &Vec3<N>) {
        let xaxis = at.normalized();
        let zaxis = up.cross(&xaxis).normalized();
        let yaxis = zaxis.cross(&xaxis);

        self.submat = Mat3::new(xaxis.x.clone(), yaxis.x.clone(), zaxis.x.clone(),
        xaxis.y.clone(), yaxis.y.clone(), zaxis.y.clone(),
        xaxis.z        , yaxis.z        , zaxis.z)
    }

    /// Reorient this matrix such that its local `z` axis points to a given point.
    ///
    /// # Arguments
    ///   * at - The point to look at. It is also the direction the matrix `y` axis will be aligned
    ///   with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at_z(&mut self, at: &Vec3<N>, up: &Vec3<N>) {
        let zaxis = at.normalized();
        let xaxis = up.cross(&zaxis).normalized();
        let yaxis = zaxis.cross(&xaxis);

        self.submat = Mat3::new(xaxis.x.clone(), yaxis.x.clone(), zaxis.x.clone(),
        xaxis.y.clone(), yaxis.y.clone(), zaxis.y.clone(),
        xaxis.z        , yaxis.z        , zaxis.z)
    }
}

impl<N: Trigonometric + Num + Clone>
Rotation<Vec1<N>> for Rotmat<Mat2<N>> {
    #[inline]
    fn rotation(&self) -> Vec1<N> {
        Vec1::new((-self.submat.at((0, 1))).atan2(&self.submat.at((0, 0))))
    }

    #[inline]
    fn inv_rotation(&self) -> Vec1<N> {
        -self.rotation()
    }

    #[inline]
    fn rotate_by(&mut self, rot: &Vec1<N>) {
        *self = self.rotated(rot)
    }

    #[inline]
    fn rotated(&self, rot: &Vec1<N>) -> Rotmat<Mat2<N>> {
        Rotmat::from_angle(rot.x.clone()) * *self
    }

    #[inline]
    fn set_rotation(&mut self, rot: Vec1<N>) {
        *self = Rotmat::from_angle(rot.x)
    }
}

impl<N: Clone + Trigonometric + Num + Algebraic>
Rotation<Vec3<N>> for Rotmat<Mat3<N>> {
    #[inline]
    fn rotation(&self) -> Vec3<N> {
        fail!("Not yet implemented.")
    }

    #[inline]
    fn inv_rotation(&self) -> Vec3<N> {
        fail!("Not yet implemented.")
    }

    #[inline]
    fn rotate_by(&mut self, rot: &Vec3<N>) {
        *self = self.rotated(rot)
    }

    #[inline]
    fn rotated(&self, axisangle: &Vec3<N>) -> Rotmat<Mat3<N>> {
        Rotmat::from_axis_angle(axisangle.clone()) * *self
    }

    #[inline]
    fn set_rotation(&mut self, axisangle: Vec3<N>) {
        *self = Rotmat::from_axis_angle(axisangle)
    }
}

impl<N: Clone + Rand + Trigonometric + Neg<N>> Rand for Rotmat<Mat2<N>> {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Rotmat<Mat2<N>> {
        Rotmat::from_angle(rng.gen())
    }
}

impl<M: RMul<V> + LMul<V>, V> Rotate<V> for Rotmat<M> {
    #[inline]
    fn rotate(&self, v: &V) -> V {
        self.rmul(v)
    }

    #[inline]
    fn inv_rotate(&self, v: &V) -> V {
        self.lmul(v)
    }
}

impl<M: RMul<V> + LMul<V>, V> Transform<V> for Rotmat<M> {
    #[inline]
    fn transform(&self, v: &V) -> V {
        self.rotate(v)
    }

    #[inline]
    fn inv_transform(&self, v: &V) -> V {
        self.inv_rotate(v)
    }
}

impl<N: Clone + Rand + Trigonometric + Num + Algebraic>
Rand for Rotmat<Mat3<N>> {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Rotmat<Mat3<N>> {
        Rotmat::from_axis_angle(rng.gen())
    }
}

impl<M: Dim> Dim for Rotmat<M> {
    #[inline]
    fn dim(_: Option<Rotmat<M>>) -> uint {
        Dim::dim(None::<M>)
    }
}

impl<M: One + Zero> One for Rotmat<M> {
    #[inline]
    fn one() -> Rotmat<M> {
        Rotmat { submat: One::one() }
    }
}

impl<M: Mul<M, M>> Mul<Rotmat<M>, Rotmat<M>> for Rotmat<M> {
    #[inline]
    fn mul(&self, other: &Rotmat<M>) -> Rotmat<M> {
        Rotmat { submat: self.submat.mul(&other.submat) }
    }
}

impl<V, M: RMul<V>> RMul<V> for Rotmat<M> {
    #[inline]
    fn rmul(&self, other: &V) -> V {
        self.submat.rmul(other)
    }
}

impl<V, M: LMul<V>> LMul<V> for Rotmat<M> {
    #[inline]
    fn lmul(&self, other: &V) -> V {
        self.submat.lmul(other)
    }
}

impl<M: Transpose> Inv for Rotmat<M> {
    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        self.transpose();

        true
    }

    #[inline]
    fn inverse(&self) -> Option<Rotmat<M>> {
        Some(self.transposed())
    }
}

impl<M: Transpose>
Transpose for Rotmat<M> {
    #[inline]
    fn transposed(&self) -> Rotmat<M> {
        Rotmat { submat: self.submat.transposed() }
    }

    #[inline]
    fn transpose(&mut self) {
        self.submat.transpose()
    }
}

// we loose the info that we are a rotation matrix
impl<M: ToHomogeneous<M2>, M2> ToHomogeneous<M2> for Rotmat<M> {
    fn to_homogeneous(&self) -> M2 {
        self.submat.to_homogeneous()
    }
}

impl<N: ApproxEq<N>, M: ApproxEq<N>> ApproxEq<N> for Rotmat<M> {
    #[inline]
    fn approx_epsilon() -> N {
        // ApproxEq::<N>::approx_epsilon()
        fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.")
    }

    #[inline]
    fn approx_eq(&self, other: &Rotmat<M>) -> bool {
        self.submat.approx_eq(&other.submat)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Rotmat<M>, epsilon: &N) -> bool {
        self.submat.approx_eq_eps(&other.submat, epsilon)
    }
}
<commit_msg>Implement 3d rotation matrix -> axis angle conversion.<commit_after>use std::num::{One, Zero};
use std::rand::{Rand, Rng, RngUtil};
use std::cmp::ApproxEq;
use traits::rlmul::{RMul, LMul};
use traits::cross::Cross;
use traits::dim::Dim;
use traits::inv::Inv;
use traits::transpose::Transpose;
use traits::rotation::{Rotation, Rotate};
use traits::transformation::{Transform}; // FIXME: implement Transformation and Transformable
use traits::homogeneous::ToHomogeneous;
use traits::indexable::Indexable;
use traits::vector::AlgebraicVec;
use vec::Vec1;
use mat::{Mat2, Mat3};
use vec::Vec3;

/// Matrix wrapper representing rotation matrix. It is built uppon another matrix and ensures (at
/// the type-level) that it will always represent a rotation. Rotation matrices have some
/// properties useful for performances, like the fact that the inversion is simply a transposition.
#[deriving(Eq, ToStr, Clone)]
pub struct Rotmat<M> {
    priv submat: M
}

impl<M: Clone> Rotmat<M> {
    /// Gets a copy of the internal representation of the rotation.
    pub fn submat(&self) -> M {
        self.submat.clone()
    }
}

impl<N: Clone + Trigonometric + Neg<N>> Rotmat<Mat2<N>> {
    /// Builds a 2 dimensional rotation matrix from an angle in radian.
    pub fn from_angle(angle: N) -> Rotmat<Mat2<N>> {
        let (sia, coa) = angle.sin_cos();

        Rotmat {
            submat: Mat2::new(coa.clone(), -sia, sia.clone(), coa)
        }
    }
}

impl<N: Clone + Trigonometric + Num + Algebraic> Rotmat<Mat3<N>> {
    /// Builds a 3 dimensional rotation matrix from an axis and an angle.
    ///
    /// # Arguments
    ///   * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation
    ///   in radian. Its direction is the axis of rotation.
    pub fn from_axis_angle(axisangle: Vec3<N>) -> Rotmat<Mat3<N>> {
        if axisangle.sqnorm().is_zero() {
            One::one()
        }
        else {
            let mut axis   = axisangle;
            let angle      = axis.normalize();
            let _1: N      = One::one();
            let ux         = axis.x.clone();
            let uy         = axis.y.clone();
            let uz         = axis.z.clone();
            let sqx        = ux * ux;
            let sqy        = uy * uy;
            let sqz        = uz * uz;
            let (sin, cos) = angle.sin_cos();
            let one_m_cos  = _1 - cos;

            Rotmat {
                submat: Mat3::new(
                            (sqx + (_1 - sqx) * cos),
                            (ux * uy * one_m_cos - uz * sin),
                            (ux * uz * one_m_cos + uy * sin),

                            (ux * uy * one_m_cos + uz * sin),
                            (sqy + (_1 - sqy) * cos),
                            (uy * uz * one_m_cos - ux * sin),

                            (ux * uz * one_m_cos - uy * sin),
                            (uy * uz * one_m_cos + ux * sin),
                            (sqz + (_1 - sqz) * cos))
            }
        }
    }
}

impl<N: Clone + Num + Algebraic> Rotmat<Mat3<N>> {
    /// Reorient this matrix such that its local `x` axis points to a given point. Note that the
    /// usually known `look_at` function does the same thing but with the `z` axis. See `look_at_z`
    /// for that.
    ///
    /// # Arguments
    ///   * at - The point to look at. It is also the direction the matrix `x` axis will be aligned
    ///   with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at(&mut self, at: &Vec3<N>, up: &Vec3<N>) {
        let xaxis = at.normalized();
        let zaxis = up.cross(&xaxis).normalized();
        let yaxis = zaxis.cross(&xaxis);

        self.submat = Mat3::new(xaxis.x.clone(), yaxis.x.clone(), zaxis.x.clone(),
        xaxis.y.clone(), yaxis.y.clone(), zaxis.y.clone(),
        xaxis.z        , yaxis.z        , zaxis.z)
    }

    /// Reorient this matrix such that its local `z` axis points to a given point.
    ///
    /// # Arguments
    ///   * at - The point to look at. It is also the direction the matrix `y` axis will be aligned
    ///   with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at_z(&mut self, at: &Vec3<N>, up: &Vec3<N>) {
        let zaxis = at.normalized();
        let xaxis = up.cross(&zaxis).normalized();
        let yaxis = zaxis.cross(&xaxis);

        self.submat = Mat3::new(xaxis.x.clone(), yaxis.x.clone(), zaxis.x.clone(),
        xaxis.y.clone(), yaxis.y.clone(), zaxis.y.clone(),
        xaxis.z        , yaxis.z        , zaxis.z)
    }
}

impl<N: Trigonometric + Num + Clone>
Rotation<Vec1<N>> for Rotmat<Mat2<N>> {
    #[inline]
    fn rotation(&self) -> Vec1<N> {
        Vec1::new((-self.submat.at((0, 1))).atan2(&self.submat.at((0, 0))))
    }

    #[inline]
    fn inv_rotation(&self) -> Vec1<N> {
        -self.rotation()
    }

    #[inline]
    fn rotate_by(&mut self, rot: &Vec1<N>) {
        *self = self.rotated(rot)
    }

    #[inline]
    fn rotated(&self, rot: &Vec1<N>) -> Rotmat<Mat2<N>> {
        Rotmat::from_angle(rot.x.clone()) * *self
    }

    #[inline]
    fn set_rotation(&mut self, rot: Vec1<N>) {
        *self = Rotmat::from_angle(rot.x)
    }
}

impl<N: Clone + Trigonometric + Num + Algebraic + NumCast>
Rotation<Vec3<N>> for Rotmat<Mat3<N>> {
    #[inline]
    fn rotation(&self) -> Vec3<N> {
        let angle = ((self.submat.m11 + self.submat.m22 + self.submat.m33 - One::one()) / NumCast::from(2.0)).acos();

        if angle != angle {
            // FIXME: handle that correctly
            Zero::zero()
        }
        else if angle.is_zero() {
            Zero::zero()
        }
        else {
            let m32_m23 = self.submat.m32 - self.submat.m23;
            let m13_m31 = self.submat.m13 - self.submat.m31;
            let m21_m12 = self.submat.m21 - self.submat.m12;

            let denom = (m32_m23 * m32_m23 + m13_m31 * m13_m31 + m21_m12 * m21_m12).sqrt();

            if denom.is_zero() {
                // XXX: handle that properly
                // fail!("Internal error: singularity.")
                Zero::zero()
            }
            else {
                let a_d = angle / denom;

                Vec3::new(m32_m23 * a_d, m13_m31 * a_d, m21_m12 * a_d)
            }
        }
    }

    #[inline]
    fn inv_rotation(&self) -> Vec3<N> {
        -self.rotation()
    }

    #[inline]
    fn rotate_by(&mut self, rot: &Vec3<N>) {
        *self = self.rotated(rot)
    }

    #[inline]
    fn rotated(&self, axisangle: &Vec3<N>) -> Rotmat<Mat3<N>> {
        Rotmat::from_axis_angle(axisangle.clone()) * *self
    }

    #[inline]
    fn set_rotation(&mut self, axisangle: Vec3<N>) {
        *self = Rotmat::from_axis_angle(axisangle)
    }
}

impl<N: Clone + Rand + Trigonometric + Neg<N>> Rand for Rotmat<Mat2<N>> {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Rotmat<Mat2<N>> {
        Rotmat::from_angle(rng.gen())
    }
}

impl<M: RMul<V> + LMul<V>, V> Rotate<V> for Rotmat<M> {
    #[inline]
    fn rotate(&self, v: &V) -> V {
        self.rmul(v)
    }

    #[inline]
    fn inv_rotate(&self, v: &V) -> V {
        self.lmul(v)
    }
}

impl<M: RMul<V> + LMul<V>, V> Transform<V> for Rotmat<M> {
    #[inline]
    fn transform(&self, v: &V) -> V {
        self.rotate(v)
    }

    #[inline]
    fn inv_transform(&self, v: &V) -> V {
        self.inv_rotate(v)
    }
}

impl<N: Clone + Rand + Trigonometric + Num + Algebraic>
Rand for Rotmat<Mat3<N>> {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Rotmat<Mat3<N>> {
        Rotmat::from_axis_angle(rng.gen())
    }
}

impl<M: Dim> Dim for Rotmat<M> {
    #[inline]
    fn dim(_: Option<Rotmat<M>>) -> uint {
        Dim::dim(None::<M>)
    }
}

impl<M: One + Zero> One for Rotmat<M> {
    #[inline]
    fn one() -> Rotmat<M> {
        Rotmat { submat: One::one() }
    }
}

impl<M: Mul<M, M>> Mul<Rotmat<M>, Rotmat<M>> for Rotmat<M> {
    #[inline]
    fn mul(&self, other: &Rotmat<M>) -> Rotmat<M> {
        Rotmat { submat: self.submat.mul(&other.submat) }
    }
}

impl<V, M: RMul<V>> RMul<V> for Rotmat<M> {
    #[inline]
    fn rmul(&self, other: &V) -> V {
        self.submat.rmul(other)
    }
}

impl<V, M: LMul<V>> LMul<V> for Rotmat<M> {
    #[inline]
    fn lmul(&self, other: &V) -> V {
        self.submat.lmul(other)
    }
}

impl<M: Transpose> Inv for Rotmat<M> {
    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        self.transpose();

        true
    }

    #[inline]
    fn inverse(&self) -> Option<Rotmat<M>> {
        Some(self.transposed())
    }
}

impl<M: Transpose>
Transpose for Rotmat<M> {
    #[inline]
    fn transposed(&self) -> Rotmat<M> {
        Rotmat { submat: self.submat.transposed() }
    }

    #[inline]
    fn transpose(&mut self) {
        self.submat.transpose()
    }
}

// we loose the info that we are a rotation matrix
impl<M: ToHomogeneous<M2>, M2> ToHomogeneous<M2> for Rotmat<M> {
    fn to_homogeneous(&self) -> M2 {
        self.submat.to_homogeneous()
    }
}

impl<N: ApproxEq<N>, M: ApproxEq<N>> ApproxEq<N> for Rotmat<M> {
    #[inline]
    fn approx_epsilon() -> N {
        // ApproxEq::<N>::approx_epsilon()
        fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.")
    }

    #[inline]
    fn approx_eq(&self, other: &Rotmat<M>) -> bool {
        self.submat.approx_eq(&other.submat)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Rotmat<M>, epsilon: &N) -> bool {
        self.submat.approx_eq_eps(&other.submat, epsilon)
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::{BlockTransaction, FullTransaction, TransactionHash};
use super::RpcBlock;
use libproto::blockchain::Block as ProtoBlock;
use libproto::blockchain::BlockHeader as ProtoBlockHeader;
use proof::CitaProof;
use protobuf::core::parse_from_bytes;
use util::H256;
use util::U256;

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct BlockBody {
    pub transactions: Vec<BlockTransaction>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct BlockHeader {
    pub timestamp: u64,
    #[serde(rename = "prevHash")]
    pub prev_hash: H256,
    pub number: U256,
    #[serde(rename = "stateRoot")]
    pub state_root: H256,
    #[serde(rename = "transactionsRoot")]
    pub transactions_root: H256,
    #[serde(rename = "receiptsRoot")]
    pub receipts_root: H256,
    #[serde(rename = "gasUsed")]
    pub gas_used: U256,
    pub proof: CitaProof,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Block {
    pub version: u32,
    pub hash: H256,
    pub header: BlockHeader,
    pub body: BlockBody,
}

impl From<ProtoBlockHeader> for BlockHeader {
    fn from(proto_header: ProtoBlockHeader) -> Self {
        BlockHeader {
            timestamp: proto_header.timestamp,
            prev_hash: H256::from(proto_header.get_prevhash()),
            number: U256::from(proto_header.get_height()),
            state_root: H256::from(proto_header.get_state_root()),
            transactions_root: H256::from(proto_header.get_transactions_root()),
            receipts_root: H256::from(proto_header.get_receipts_root()),
            gas_used: U256::from(proto_header.get_gas_used()),
            proof: proto_header.clone().take_proof().into(),
        }
    }
}

impl From<RpcBlock> for Block {
    fn from(block: RpcBlock) -> Self {
        let mut blk = parse_from_bytes::<ProtoBlock>(block.block.as_slice()).unwrap();
        let proto_header = blk.take_header();
        let mut proto_body = blk.take_body();
        let block_transactions = proto_body.take_transactions();
        let transactions = match block.include_txs {
            true => block_transactions.into_iter().map(|x| BlockTransaction::Full(FullTransaction::from(x))).collect(),
            false => block_transactions.into_iter().map(|x| BlockTransaction::Hash(TransactionHash::from(x))).collect(),
        };

        Block {
            version: blk.version,
            header: BlockHeader::from(proto_header),
            body: BlockBody { transactions: transactions },
            hash: H256::from_slice(&block.hash),
        }
    }
}
<commit_msg>fix getBlockByNumber error when the number is zero<commit_after>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::{BlockTransaction, FullTransaction, TransactionHash};
use super::RpcBlock;
use libproto::blockchain::Block as ProtoBlock;
use libproto::blockchain::BlockHeader as ProtoBlockHeader;
use proof::CitaProof;
use protobuf::core::parse_from_bytes;
use util::{H256, U256};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct BlockBody {
    pub transactions: Vec<BlockTransaction>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct BlockHeader {
    pub timestamp: u64,
    #[serde(rename = "prevHash")]
    pub prev_hash: H256,
    pub number: U256,
    #[serde(rename = "stateRoot")]
    pub state_root: H256,
    #[serde(rename = "transactionsRoot")]
    pub transactions_root: H256,
    #[serde(rename = "receiptsRoot")]
    pub receipts_root: H256,
    #[serde(rename = "gasUsed")]
    pub gas_used: U256,
    pub proof: Option<CitaProof>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Block {
    pub version: u32,
    pub hash: H256,
    pub header: BlockHeader,
    pub body: BlockBody,
}

impl From<ProtoBlockHeader> for BlockHeader {
    fn from(proto_header: ProtoBlockHeader) -> Self {
        let proof = match proto_header.get_height() {
            0 => None,
            _ => Some(proto_header.clone().take_proof().into()),
        };
        trace!("number = {}, proof = {:?}", U256::from(proto_header.get_height()), proof);

        BlockHeader {
            timestamp: proto_header.timestamp,
            prev_hash: H256::from(proto_header.get_prevhash()),
            number: U256::from(proto_header.get_height()),
            state_root: H256::from(proto_header.get_state_root()),
            transactions_root: H256::from(proto_header.get_transactions_root()),
            receipts_root: H256::from(proto_header.get_receipts_root()),
            gas_used: U256::from(proto_header.get_gas_used()),
            proof: proof,
        }
    }
}

impl From<RpcBlock> for Block {
    fn from(block: RpcBlock) -> Self {
        let mut blk = parse_from_bytes::<ProtoBlock>(block.block.as_slice()).unwrap();
        let proto_header = blk.take_header();
        let mut proto_body = blk.take_body();
        let block_transactions = proto_body.take_transactions();
        let transactions = match block.include_txs {
            true => block_transactions.into_iter().map(|x| BlockTransaction::Full(FullTransaction::from(x))).collect(),
            false => block_transactions.into_iter().map(|x| BlockTransaction::Hash(TransactionHash::from(x))).collect(),
        };

        Block {
            version: blk.version,
            header: BlockHeader::from(proto_header),
            body: BlockBody { transactions: transactions },
            hash: H256::from_slice(&block.hash),
        }
    }
}
<|endoftext|>


<commit_before>//! Endpoints for room management.

pub mod create_room;
pub mod get_room_event;
pub mod report_content;
pub mod upgrade_room;

use ruma_serde::StringEnum;

/// Whether or not a newly created room will be listed in the room directory.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
pub enum Visibility {
    /// Indicates that the room will be shown in the published room list.
    Public,

    /// Indicates that the room will not be shown in the published room list.
    Private,

    #[doc(hidden)]
    _Custom(String),
}

impl Default for Visibility {
    fn default() -> Self {
        Self::Private
    }
}
<commit_msg>client-api: Export aliases<commit_after>//! Endpoints for room management.

pub mod create_room;
pub mod get_room_event;
pub mod report_content;
pub mod upgrade_room;
pub mod aliases;

use ruma_serde::StringEnum;

/// Whether or not a newly created room will be listed in the room directory.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
pub enum Visibility {
    /// Indicates that the room will be shown in the published room list.
    Public,

    /// Indicates that the room will not be shown in the published room list.
    Private,

    #[doc(hidden)]
    _Custom(String),
}

impl Default for Visibility {
    fn default() -> Self {
        Self::Private
    }
}
<|endoftext|>