<commit_before>use std::fmt;
use std::fmt::{Show, Formatter};
use serialize::{Decodable, Decoder, Encodable, Encoder};

use url::Url;

use core::{Summary, Package, PackageId};
use sources::{PathSource, GitSource};
use sources::git;
use util::{Config, CargoResult, CargoError};
use util::errors::human;

/// A Source finds and downloads remote packages based on names and
/// versions.
pub trait Source {
    /// The update method performs any network operations required to
    /// get the entire list of all names, versions and dependencies of
    /// packages managed by the Source.
    fn update(&mut self) -> CargoResult<()>;

    /// The list method lists all names, versions and dependencies of
    /// packages managed by the source. It assumes that `update` has
    /// already been called and no additional network operations are
    /// required.
    fn list(&self) -> CargoResult<Vec<Summary>>;

    /// The download method fetches the full package for each name and
    /// version specified.
    fn download(&self, packages: &[PackageId]) -> CargoResult<()>;

    /// The get method returns the Path of each specified package on the
    /// local file system. It assumes that `download` was already called,
    /// and that the packages are already locally available on the file
    /// system.
    fn get(&self, packages: &[PackageId]) -> CargoResult<Vec<Package>>;

    /// Generates a unique string which represents the fingerprint of the
    /// current state of the source.
    ///
    /// This fingerprint is used to determine the "fresheness" of the source
    /// later on. It must be guaranteed that the fingerprint of a source is
    /// constant if and only if the output product will remain constant.
    ///
    /// The `pkg` argument is the package which this fingerprint should only be
    /// interested in for when this source may contain multiple packages.
    fn fingerprint(&self, pkg: &Package) -> CargoResult<String>;
}

#[deriving(Encodable, Decodable, Show, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SourceKind {
    /// GitKind(<git reference>) represents a git repository
    GitKind(String),
    /// represents a local path
    PathKind,
    /// represents the central registry
    RegistryKind
}

#[deriving(Clone, PartialEq, Eq, Hash)]
pub enum Location {
    Local(Path),
    Remote(Url),
}

type Error = Box<CargoError + Send>;

impl<E, D: Decoder<E>> Decodable<D, E> for Location {
    fn decode(d: &mut D) -> Result<Location, E> {
        let url: String  = raw_try!(Decodable::decode(d));
        Ok(Location::parse(url.as_slice()).unwrap())
    }
}

impl<E, S: Encoder<E>> Encodable<S, E> for Location {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        self.to_string().encode(e)
    }
}

#[deriving(Encodable, Decodable, Clone, Eq, Hash)]
pub struct SourceId {
    pub kind: SourceKind,
    pub location: Location,
}

impl Show for Location {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Local(ref p) => write!(f, "file:{}", p.display()),
            Remote(ref u) => write!(f, "{}", u),
        }
    }
}

impl Location {
    pub fn parse(s: &str) -> CargoResult<Location> {
        if s.starts_with("file:") {
            Ok(Local(Path::new(s.slice_from(5))))
        } else {
            Url::parse(s).map(Remote).map_err(|e| {
                human(format!("invalid url `{}`: `{}", s, e))
            })
        }
    }
}

impl Show for SourceId {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            SourceId { kind: PathKind, ref location } => {
                try!(write!(f, "{}", location))
            },
            SourceId { kind: GitKind(ref reference), ref location } => {
                try!(write!(f, "{}", location));
                if reference.as_slice() != "master" {
                    try!(write!(f, "#ref={}", reference));
                }
            },
            SourceId { kind: RegistryKind, .. } => {
                // TODO: Central registry vs. alternates
                try!(write!(f, "the package registry"));
            }
        }

        Ok(())
    }
}

// This custom implementation handles situations such as when two git sources
// point at *almost* the same URL, but not quite, even when they actually point
// to the same repository.
impl PartialEq for SourceId {
    fn eq(&self, other: &SourceId) -> bool {
        if self.kind != other.kind { return false }
        if self.location == other.location { return true }

        match (&self.kind, &other.kind, &self.location, &other.location) {
            (&GitKind(..), &GitKind(..),
             &Remote(ref u1), &Remote(ref u2)) => {
                git::canonicalize_url(u1.to_string().as_slice()) ==
                    git::canonicalize_url(u2.to_string().as_slice())
            }
            _ => false,
        }
    }
}

impl SourceId {
    pub fn new(kind: SourceKind, location: Location) -> SourceId {
        SourceId { kind: kind, location: location }
    }

    // Pass absolute path
    pub fn for_path(path: &Path) -> SourceId {
        SourceId::new(PathKind, Local(path.clone()))
    }

    pub fn for_git(url: &Url, reference: &str) -> SourceId {
        SourceId::new(GitKind(reference.to_string()), Remote(url.clone()))
    }

    pub fn for_central() -> SourceId {
        SourceId::new(RegistryKind,
                      Remote(Url::parse("https://example.com").unwrap()))
    }

    pub fn get_location<'a>(&'a self) -> &'a Location {
        &self.location
    }

    pub fn is_path(&self) -> bool {
        self.kind == PathKind
    }

    pub fn is_git(&self) -> bool {
        match self.kind {
            GitKind(_) => true,
            _ => false
        }
    }

    pub fn load(&self, config: &mut Config) -> Box<Source> {
        match self.kind {
            GitKind(..) => box GitSource::new(self, config) as Box<Source>,
            PathKind => {
                let path = match self.location {
                    Local(ref p) => p,
                    Remote(..) => fail!("path sources cannot be remote"),
                };
                box PathSource::new(path, self) as Box<Source>
            },
            RegistryKind => unimplemented!()
        }
    }
}

pub struct SourceSet {
    sources: Vec<Box<Source>>
}

impl SourceSet {
    pub fn new(sources: Vec<Box<Source>>) -> SourceSet {
        SourceSet { sources: sources }
    }
}

impl Source for SourceSet {
    fn update(&mut self) -> CargoResult<()> {
        for source in self.sources.mut_iter() {
            try!(source.update());
        }

        Ok(())
    }

    fn list(&self) -> CargoResult<Vec<Summary>> {
        let mut ret = Vec::new();

        for source in self.sources.iter() {
            ret.push_all(try!(source.list()).as_slice());
        }

        Ok(ret)
    }

    fn download(&self, packages: &[PackageId]) -> CargoResult<()> {
        for source in self.sources.iter() {
            try!(source.download(packages));
        }

        Ok(())
    }

    fn get(&self, packages: &[PackageId]) -> CargoResult<Vec<Package>> {
        let mut ret = Vec::new();

        for source in self.sources.iter() {
            ret.push_all(try!(source.get(packages)).as_slice());
        }

        Ok(ret)
    }

    fn fingerprint(&self, id: &Package) -> CargoResult<String> {
        let mut ret = String::new();
        for source in self.sources.iter() {
            ret.push_str(try!(source.fingerprint(id)).as_slice());
        }
        return Ok(ret);
    }
}

#[cfg(test)]
mod tests {
    use super::{SourceId, Remote, GitKind};

    #[test]
    fn github_sources_equal() {
        let loc = Remote(from_str("https://github.com/foo/bar").unwrap());
        let s1 = SourceId::new(GitKind("master".to_string()), loc);

        let loc = Remote(from_str("git://github.com/foo/bar").unwrap());
        let mut s2 = SourceId::new(GitKind("master".to_string()), loc);

        assert_eq!(s1, s2);

        s2.kind = GitKind("foo".to_string());
        assert!(s1 != s2);
    }
}
<commit_msg>Canonicalize URLs when hashing sources<commit_after>use std::fmt;
use std::fmt::{Show, Formatter};
use std::hash;
use serialize::{Decodable, Decoder, Encodable, Encoder};

use url::Url;

use core::{Summary, Package, PackageId};
use sources::{PathSource, GitSource};
use sources::git;
use util::{Config, CargoResult, CargoError};
use util::errors::human;

/// A Source finds and downloads remote packages based on names and
/// versions.
pub trait Source {
    /// The update method performs any network operations required to
    /// get the entire list of all names, versions and dependencies of
    /// packages managed by the Source.
    fn update(&mut self) -> CargoResult<()>;

    /// The list method lists all names, versions and dependencies of
    /// packages managed by the source. It assumes that `update` has
    /// already been called and no additional network operations are
    /// required.
    fn list(&self) -> CargoResult<Vec<Summary>>;

    /// The download method fetches the full package for each name and
    /// version specified.
    fn download(&self, packages: &[PackageId]) -> CargoResult<()>;

    /// The get method returns the Path of each specified package on the
    /// local file system. It assumes that `download` was already called,
    /// and that the packages are already locally available on the file
    /// system.
    fn get(&self, packages: &[PackageId]) -> CargoResult<Vec<Package>>;

    /// Generates a unique string which represents the fingerprint of the
    /// current state of the source.
    ///
    /// This fingerprint is used to determine the "fresheness" of the source
    /// later on. It must be guaranteed that the fingerprint of a source is
    /// constant if and only if the output product will remain constant.
    ///
    /// The `pkg` argument is the package which this fingerprint should only be
    /// interested in for when this source may contain multiple packages.
    fn fingerprint(&self, pkg: &Package) -> CargoResult<String>;
}

#[deriving(Encodable, Decodable, Show, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SourceKind {
    /// GitKind(<git reference>) represents a git repository
    GitKind(String),
    /// represents a local path
    PathKind,
    /// represents the central registry
    RegistryKind
}

#[deriving(Clone, PartialEq, Eq, Hash)]
pub enum Location {
    Local(Path),
    Remote(Url),
}

type Error = Box<CargoError + Send>;

impl<E, D: Decoder<E>> Decodable<D, E> for Location {
    fn decode(d: &mut D) -> Result<Location, E> {
        let url: String  = raw_try!(Decodable::decode(d));
        Ok(Location::parse(url.as_slice()).unwrap())
    }
}

impl<E, S: Encoder<E>> Encodable<S, E> for Location {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        self.to_string().encode(e)
    }
}

#[deriving(Encodable, Decodable, Clone, Eq)]
pub struct SourceId {
    pub kind: SourceKind,
    pub location: Location,
}

impl Show for Location {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Local(ref p) => write!(f, "file:{}", p.display()),
            Remote(ref u) => write!(f, "{}", u),
        }
    }
}

impl Location {
    pub fn parse(s: &str) -> CargoResult<Location> {
        if s.starts_with("file:") {
            Ok(Local(Path::new(s.slice_from(5))))
        } else {
            Url::parse(s).map(Remote).map_err(|e| {
                human(format!("invalid url `{}`: `{}", s, e))
            })
        }
    }
}

impl Show for SourceId {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            SourceId { kind: PathKind, ref location } => {
                try!(write!(f, "{}", location))
            },
            SourceId { kind: GitKind(ref reference), ref location } => {
                try!(write!(f, "{}", location));
                if reference.as_slice() != "master" {
                    try!(write!(f, "#ref={}", reference));
                }
            },
            SourceId { kind: RegistryKind, .. } => {
                // TODO: Central registry vs. alternates
                try!(write!(f, "the package registry"));
            }
        }

        Ok(())
    }
}

// This custom implementation handles situations such as when two git sources
// point at *almost* the same URL, but not quite, even when they actually point
// to the same repository.
impl PartialEq for SourceId {
    fn eq(&self, other: &SourceId) -> bool {
        if self.kind != other.kind { return false }
        if self.location == other.location { return true }

        match (&self.kind, &other.kind, &self.location, &other.location) {
            (&GitKind(..), &GitKind(..),
             &Remote(ref u1), &Remote(ref u2)) => {
                git::canonicalize_url(u1.to_string().as_slice()) ==
                    git::canonicalize_url(u2.to_string().as_slice())
            }
            _ => false,
        }
    }
}

impl<S: hash::Writer> hash::Hash<S> for SourceId {
    fn hash(&self, into: &mut S) {
        match *self {
            SourceId {
                kind: ref kind @ GitKind(..),
                location: Remote(ref url)
            } => {
                kind.hash(into);
                git::canonicalize_url(url.to_string().as_slice()).hash(into);
            }
            _ => {
                self.kind.hash(into);
                self.location.hash(into);
            }
        }
    }
}

impl SourceId {
    pub fn new(kind: SourceKind, location: Location) -> SourceId {
        SourceId { kind: kind, location: location }
    }

    // Pass absolute path
    pub fn for_path(path: &Path) -> SourceId {
        SourceId::new(PathKind, Local(path.clone()))
    }

    pub fn for_git(url: &Url, reference: &str) -> SourceId {
        SourceId::new(GitKind(reference.to_string()), Remote(url.clone()))
    }

    pub fn for_central() -> SourceId {
        SourceId::new(RegistryKind,
                      Remote(Url::parse("https://example.com").unwrap()))
    }

    pub fn get_location<'a>(&'a self) -> &'a Location {
        &self.location
    }

    pub fn is_path(&self) -> bool {
        self.kind == PathKind
    }

    pub fn is_git(&self) -> bool {
        match self.kind {
            GitKind(_) => true,
            _ => false
        }
    }

    pub fn load(&self, config: &mut Config) -> Box<Source> {
        match self.kind {
            GitKind(..) => box GitSource::new(self, config) as Box<Source>,
            PathKind => {
                let path = match self.location {
                    Local(ref p) => p,
                    Remote(..) => fail!("path sources cannot be remote"),
                };
                box PathSource::new(path, self) as Box<Source>
            },
            RegistryKind => unimplemented!()
        }
    }
}

pub struct SourceSet {
    sources: Vec<Box<Source>>
}

impl SourceSet {
    pub fn new(sources: Vec<Box<Source>>) -> SourceSet {
        SourceSet { sources: sources }
    }
}

impl Source for SourceSet {
    fn update(&mut self) -> CargoResult<()> {
        for source in self.sources.mut_iter() {
            try!(source.update());
        }

        Ok(())
    }

    fn list(&self) -> CargoResult<Vec<Summary>> {
        let mut ret = Vec::new();

        for source in self.sources.iter() {
            ret.push_all(try!(source.list()).as_slice());
        }

        Ok(ret)
    }

    fn download(&self, packages: &[PackageId]) -> CargoResult<()> {
        for source in self.sources.iter() {
            try!(source.download(packages));
        }

        Ok(())
    }

    fn get(&self, packages: &[PackageId]) -> CargoResult<Vec<Package>> {
        let mut ret = Vec::new();

        for source in self.sources.iter() {
            ret.push_all(try!(source.get(packages)).as_slice());
        }

        Ok(ret)
    }

    fn fingerprint(&self, id: &Package) -> CargoResult<String> {
        let mut ret = String::new();
        for source in self.sources.iter() {
            ret.push_str(try!(source.fingerprint(id)).as_slice());
        }
        return Ok(ret);
    }
}

#[cfg(test)]
mod tests {
    use super::{SourceId, Remote, GitKind};

    #[test]
    fn github_sources_equal() {
        let loc = Remote(from_str("https://github.com/foo/bar").unwrap());
        let s1 = SourceId::new(GitKind("master".to_string()), loc);

        let loc = Remote(from_str("git://github.com/foo/bar").unwrap());
        let mut s2 = SourceId::new(GitKind("master".to_string()), loc);

        assert_eq!(s1, s2);

        s2.kind = GitKind("foo".to_string());
        assert!(s1 != s2);
    }
}
<|endoftext|>


<commit_before>use core::{Summary,NameVer,Package};
use util::CargoResult;

/**
 * A Source finds and downloads remote packages based on names and
 * versions.
 */
pub trait Source {
    /**
     * The update method performs any network operations required to
     * get the entire list of all names, versions and dependencies of
     * packages managed by the Source.
     */
    fn update(&self) -> CargoResult<()>;

    /**
     * The list method lists all names, versions and dependencies of
     * packages managed by the source. It assumes that `update` has
     * already been called and no additional network operations are
     * required.
     */
    fn list(&self) -> CargoResult<Vec<Summary>>;

    /**
     * The download method fetches the full package for each name and
     * version specified.
     */
    fn download(&self, packages: &[NameVer]) -> CargoResult<()>;

    /**
     * The get method returns the Path of each specified package on the
     * local file system. It assumes that `download` was already called,
     * and that the packages are already locally available on the file
     * system.
     */
    fn get(&self, packages: &[NameVer]) -> CargoResult<Vec<Package>>;
}
<commit_msg>Initial pass at a source collection proxy<commit_after>use core::{Summary,NameVer,Package};
use util::CargoResult;

/**
 * A Source finds and downloads remote packages based on names and
 * versions.
 */
pub trait Source {
    /**
     * The update method performs any network operations required to
     * get the entire list of all names, versions and dependencies of
     * packages managed by the Source.
     */
    fn update(&self) -> CargoResult<()>;

    /**
     * The list method lists all names, versions and dependencies of
     * packages managed by the source. It assumes that `update` has
     * already been called and no additional network operations are
     * required.
     */
    fn list(&self) -> CargoResult<Vec<Summary>>;

    /**
     * The download method fetches the full package for each name and
     * version specified.
     */
    fn download(&self, packages: &[NameVer]) -> CargoResult<()>;

    /**
     * The get method returns the Path of each specified package on the
     * local file system. It assumes that `download` was already called,
     * and that the packages are already locally available on the file
     * system.
     */
    fn get(&self, packages: &[NameVer]) -> CargoResult<Vec<Package>>;
}

impl Source for Vec<Box<Source>> {

    fn update(&self) -> CargoResult<()> {
        for source in self.iter() {
            try!(source.update());
        }

        Ok(())
    }

    fn list(&self) -> CargoResult<Vec<Summary>> {
        let mut ret = Vec::new();

        for source in self.iter() {
            ret.push_all(try!(source.list()).as_slice());
        }

        Ok(ret)
    }

    fn download(&self, packages: &[NameVer]) -> CargoResult<()> {
        for source in self.iter() {
            try!(source.download(packages));
        }

        Ok(())
    }

    fn get(&self, packages: &[NameVer]) -> CargoResult<Vec<Package>> {
        let mut ret = Vec::new();

        for source in self.iter() {
            ret.push_all(try!(source.get(packages)).as_slice());
        }

        Ok(ret)
    }
}
<|endoftext|>


<commit_before>extern crate cryptocurrency;
extern crate exonum;
extern crate exonum_harness;
extern crate iron;

use exonum::crypto::{self, PublicKey, SecretKey};
use exonum::messages::Message;
use exonum_harness::{TestHarness, HarnessApi};

use cryptocurrency::{TxCreateWallet, TxTransfer, TransactionResponse, Wallet, blockchain};

fn create_wallet(api: &HarnessApi, name: &str) -> (TxCreateWallet, SecretKey) {
    let (pubkey, key) = crypto::gen_keypair();
    // Create a presigned transaction
    let tx = TxCreateWallet::new(&pubkey, name, &key);

    let tx_info: TransactionResponse = api.post("cryptocurrency", "v1/wallets/transaction", &tx);
    assert_eq!(tx_info.tx_hash, tx.hash());

    (tx, key)
}

fn get_wallet(api: &HarnessApi, pubkey: &PublicKey) -> Wallet {
    api.get(
        "cryptocurrency",
        &format!("v1/wallet/{}", pubkey.to_string()),
    )
}

#[test]
fn test_create_wallet() {
    let mut harness = TestHarness::new(blockchain());
    let api = harness.api();
    let (tx, _) = create_wallet(&api, "Alice");

    harness.create_block();

    // Check that the user indeed is persisted by the service
    let wallet = get_wallet(&api, tx.pub_key());
    assert_eq!(wallet.pub_key(), tx.pub_key());
    assert_eq!(wallet.name(), tx.name());
    assert_eq!(wallet.balance(), 100);
}

#[test]
fn test_transfer() {
    let mut harness = TestHarness::new(blockchain());
    let api = harness.api();
    let (tx_alice, key_alice) = create_wallet(&api, "Alice");
    let (tx_bob, _) = create_wallet(&api, "Bob");

    harness.create_block();

    // Check that the initial Alice's and Bob's balances persisted by the service
    let wallet = get_wallet(&api, tx_alice.pub_key());
    assert_eq!(wallet.balance(), 100);
    let wallet = get_wallet(&api, tx_bob.pub_key());
    assert_eq!(wallet.balance(), 100);

    // Transfer funds
    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        10, // amount
        0, // seed
        &key_alice,
    );
    let tx_info: TransactionResponse = api.post("cryptocurrency", "v1/wallets/transaction", &tx);
    assert_eq!(tx_info.tx_hash, tx.hash());

    harness.create_block();

    let wallet = get_wallet(&api, tx_alice.pub_key());
    assert_eq!(wallet.balance(), 90);
    let wallet = get_wallet(&api, tx_bob.pub_key());
    assert_eq!(wallet.balance(), 110);
}
<commit_msg>Update tests to work with exonum-testkit<commit_after>extern crate cryptocurrency;
extern crate exonum;
#[macro_use]
extern crate exonum_testkit;

use exonum::crypto::{self, PublicKey, SecretKey};
use exonum::messages::Message;
use exonum_testkit::{ApiKind, TestKit, TestKitApi, TestKitBuilder};

use cryptocurrency::{TxCreateWallet, TxTransfer, TransactionResponse, Wallet, CurrencyService};

struct CryptocurrencyApi {
    inner: TestKitApi,
}

impl CryptocurrencyApi {
    fn create_wallet(&self, name: &str) -> (TxCreateWallet, SecretKey) {
        let (pubkey, key) = crypto::gen_keypair();
        // Create a presigned transaction
        let tx = TxCreateWallet::new(&pubkey, name, &key);

        let tx_info: TransactionResponse = self.inner.post(
            ApiKind::Service("cryptocurrency"),
            "v1/wallets",
            &tx,
        );
        assert_eq!(tx_info.tx_hash, tx.hash());
        (tx, key)
    }

    fn get_wallet(&self, pubkey: &PublicKey) -> Wallet {
        self.inner.get(
            ApiKind::Service("cryptocurrency"),
            &format!("v1/wallet/{}", pubkey.to_string()),
        )
    }
}

fn create_testkit() -> (TestKit, CryptocurrencyApi) {
    let testkit = TestKitBuilder::validator()
        .with_service(CurrencyService)
        .create();
    let api = CryptocurrencyApi { inner: testkit.api() };
    (testkit, api)
}

#[test]
fn test_create_wallet() {
    let (mut testkit, api) = create_testkit();
    let (tx, _) = api.create_wallet("Alice");
    testkit.create_block();

    // Check that the user indeed is persisted by the service
    let wallet = api.get_wallet(tx.pub_key());
    assert_eq!(wallet.pub_key(), tx.pub_key());
    assert_eq!(wallet.name(), tx.name());
    assert_eq!(wallet.balance(), 100);
}

#[test]
fn test_transfer() {
    let (mut testkit, api) = create_testkit();
    let (tx_alice, key_alice) = api.create_wallet("Alice");
    let (tx_bob, _) = api.create_wallet("Bob");
    testkit.create_block();

    // Check that the initial Alice's and Bob's balances persisted by the service
    let wallet = api.get_wallet(tx_alice.pub_key());
    assert_eq!(wallet.balance(), 100);
    let wallet = api.get_wallet(tx_bob.pub_key());
    assert_eq!(wallet.balance(), 100);

    // Transfer funds
    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        10, // amount
        0, // seed
        &key_alice,
    );
    testkit.create_block_with_transactions(txvec![tx]);

    let wallet = api.get_wallet(tx_alice.pub_key());
    assert_eq!(wallet.balance(), 90);
    let wallet = api.get_wallet(tx_bob.pub_key());
    assert_eq!(wallet.balance(), 110);
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap, HashSet};
use std::rc::Rc;

#[allow(unused_imports)] // "ensure" seems to require "bail" be in scope (macro hygiene issue?)
use failure::{bail, ensure};
use log::debug;

use crate::core::interning::InternedString;
use crate::core::{Dependency, FeatureValue, PackageId, SourceId, Summary};
use crate::util::CargoResult;
use crate::util::Graph;

use super::errors::ActivateResult;
use super::types::{ConflictReason, DepInfo, GraphNode, Method, RcList, RegistryQueryer};

pub use super::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
pub use super::encode::{Metadata, WorkspaceResolve};
pub use super::resolve::Resolve;

// A `Context` is basically a bunch of local resolution information which is
// kept around for all `BacktrackFrame` instances. As a result, this runs the
// risk of being cloned *a lot* so we want to make this as cheap to clone as
// possible.
#[derive(Clone)]
pub struct Context {
    pub activations: Activations,
    pub resolve_features: im_rc::HashMap<PackageId, Rc<HashSet<InternedString>>>,
    pub links: im_rc::HashMap<InternedString, PackageId>,

    // These are two cheaply-cloneable lists (O(1) clone) which are effectively
    // hash maps but are built up as "construction lists". We'll iterate these
    // at the very end and actually construct the map that we're making.
    pub resolve_graph: RcList<GraphNode>,
    pub resolve_replacements: RcList<(PackageId, PackageId)>,

    // These warnings are printed after resolution.
    pub warnings: RcList<String>,
}

pub type Activations = im_rc::HashMap<(InternedString, SourceId), Rc<Vec<Summary>>>;

impl Context {
    pub fn new() -> Context {
        Context {
            resolve_graph: RcList::new(),
            resolve_features: im_rc::HashMap::new(),
            links: im_rc::HashMap::new(),
            resolve_replacements: RcList::new(),
            activations: im_rc::HashMap::new(),
            warnings: RcList::new(),
        }
    }

    /// Activate this summary by inserting it into our list of known activations.
    ///
    /// Returns true if this summary with the given method is already activated.
    pub fn flag_activated(&mut self, summary: &Summary, method: &Method<'_>) -> CargoResult<bool> {
        let id = summary.package_id();
        let prev = self
            .activations
            .entry((id.name(), id.source_id()))
            .or_insert_with(|| Rc::new(Vec::new()));
        if !prev.iter().any(|c| c == summary) {
            self.resolve_graph.push(GraphNode::Add(id));
            if let Some(link) = summary.links() {
                ensure!(
                    self.links.insert(link, id).is_none(),
                    "Attempting to resolve a with more then one crate with the links={}. \n\
                     This will not build as is. Consider rebuilding the .lock file.",
                    &*link
                );
            }
            Rc::make_mut(prev).push(summary.clone());
            return Ok(false);
        }
        debug!("checking if {} is already activated", summary.package_id());
        let (features, use_default) = match *method {
            Method::Everything
            | Method::Required {
                all_features: true, ..
            } => return Ok(false),
            Method::Required {
                features,
                uses_default_features,
                ..
            } => (features, uses_default_features),
        };

        let has_default_feature = summary.features().contains_key("default");
        Ok(match self.resolve_features.get(&id) {
            Some(prev) => {
                features.iter().all(|f| prev.contains(f))
                    && (!use_default || prev.contains("default") || !has_default_feature)
            }
            None => features.is_empty() && (!use_default || !has_default_feature),
        })
    }

    pub fn build_deps(
        &mut self,
        registry: &mut RegistryQueryer<'_>,
        parent: Option<&Summary>,
        candidate: &Summary,
        method: &Method<'_>,
    ) -> ActivateResult<Vec<DepInfo>> {
        // First, figure out our set of dependencies based on the requested set
        // of features. This also calculates what features we're going to enable
        // for our own dependencies.
        let deps = self.resolve_features(parent, candidate, method)?;

        // Next, transform all dependencies into a list of possible candidates
        // which can satisfy that dependency.
        let mut deps = deps
            .into_iter()
            .map(|(dep, features)| {
                let candidates = registry.query(&dep)?;
                Ok((dep, candidates, Rc::new(features)))
            })
            .collect::<CargoResult<Vec<DepInfo>>>()?;

        // Attempt to resolve dependencies with fewer candidates before trying
        // dependencies with more candidates.  This way if the dependency with
        // only one candidate can't be resolved we don't have to do a bunch of
        // work before we figure that out.
        deps.sort_by_key(|&(_, ref a, _)| a.len());

        Ok(deps)
    }

    pub fn prev_active(&self, dep: &Dependency) -> &[Summary] {
        self.activations
            .get(&(dep.package_name(), dep.source_id()))
            .map(|v| &v[..])
            .unwrap_or(&[])
    }

    pub fn is_active(&self, id: PackageId) -> bool {
        self.activations
            .get(&(id.name(), id.source_id()))
            .map(|v| v.iter().any(|s| s.package_id() == id))
            .unwrap_or(false)
    }

    /// checks whether all of `parent` and the keys of `conflicting activations`
    /// are still active
    pub fn is_conflicting(
        &self,
        parent: Option<PackageId>,
        conflicting_activations: &BTreeMap<PackageId, ConflictReason>,
    ) -> bool {
        conflicting_activations
            .keys()
            .chain(parent.as_ref())
            .all(|&id| self.is_active(id))
    }

    /// Return all dependencies and the features we want from them.
    fn resolve_features<'b>(
        &mut self,
        parent: Option<&Summary>,
        s: &'b Summary,
        method: &'b Method<'_>,
    ) -> ActivateResult<Vec<(Dependency, Vec<InternedString>)>> {
        let dev_deps = match *method {
            Method::Everything => true,
            Method::Required { dev_deps, .. } => dev_deps,
        };

        // First, filter by dev-dependencies
        let deps = s.dependencies();
        let deps = deps.iter().filter(|d| d.is_transitive() || dev_deps);

        let reqs = build_requirements(s, method)?;
        let mut ret = Vec::new();
        let mut used_features = HashSet::new();
        let default_dep = (false, Vec::new());

        // Next, collect all actually enabled dependencies and their features.
        for dep in deps {
            // Skip optional dependencies, but not those enabled through a
            // feature
            if dep.is_optional() && !reqs.deps.contains_key(&dep.name_in_toml()) {
                continue;
            }
            // So we want this dependency. Move the features we want from
            // `feature_deps` to `ret` and register ourselves as using this
            // name.
            let base = reqs.deps.get(&dep.name_in_toml()).unwrap_or(&default_dep);
            used_features.insert(dep.name_in_toml());
            let always_required = !dep.is_optional()
                && !s
                    .dependencies()
                    .iter()
                    .any(|d| d.is_optional() && d.name_in_toml() == dep.name_in_toml());
            if always_required && base.0 {
                self.warnings.push(format!(
                    "Package `{}` does not have feature `{}`. It has a required dependency \
                     with that name, but only optional dependencies can be used as features. \
                     This is currently a warning to ease the transition, but it will become an \
                     error in the future.",
                    s.package_id(),
                    dep.name_in_toml()
                ));
            }
            let mut base = base.1.clone();
            base.extend(dep.features().iter());
            for feature in base.iter() {
                if feature.contains('/') {
                    return Err(failure::format_err!(
                        "feature names may not contain slashes: `{}`",
                        feature
                    )
                    .into());
                }
            }
            ret.push((dep.clone(), base));
        }

        // Any entries in `reqs.dep` which weren't used are bugs in that the
        // package does not actually have those dependencies. We classified
        // them as dependencies in the first place because there is no such
        // feature, either.
        let remaining = reqs
            .deps
            .keys()
            .cloned()
            .filter(|s| !used_features.contains(s))
            .collect::<Vec<_>>();
        if !remaining.is_empty() {
            let features = remaining.join(", ");
            return Err(match parent {
                None => failure::format_err!(
                    "Package `{}` does not have these features: `{}`",
                    s.package_id(),
                    features
                )
                .into(),
                Some(p) => (p.package_id(), ConflictReason::MissingFeatures(features)).into(),
            });
        }

        // Record what list of features is active for this package.
        if !reqs.used.is_empty() {
            let pkgid = s.package_id();

            let set = Rc::make_mut(
                self.resolve_features
                    .entry(pkgid)
                    .or_insert_with(|| Rc::new(HashSet::new())),
            );

            for feature in reqs.used {
                set.insert(feature);
            }
        }

        Ok(ret)
    }

    pub fn resolve_replacements(&self) -> HashMap<PackageId, PackageId> {
        let mut replacements = HashMap::new();
        let mut cur = &self.resolve_replacements;
        while let Some(ref node) = cur.head {
            let (k, v) = node.0;
            replacements.insert(k, v);
            cur = &node.1;
        }
        replacements
    }

    pub fn graph(&self) -> Graph<PackageId, Vec<Dependency>> {
        let mut graph: Graph<PackageId, Vec<Dependency>> = Graph::new();
        let mut cur = &self.resolve_graph;
        while let Some(ref node) = cur.head {
            match node.0 {
                GraphNode::Add(ref p) => graph.add(p.clone()),
                GraphNode::Link(ref a, ref b, ref dep) => {
                    graph.link(a.clone(), b.clone()).push(dep.clone());
                }
            }
            cur = &node.1;
        }
        graph
    }
}

/// Takes requested features for a single package from the input Method and
/// recurses to find all requested features, dependencies and requested
/// dependency features in a Requirements object, returning it to the resolver.
fn build_requirements<'a, 'b: 'a>(
    s: &'a Summary,
    method: &'b Method<'_>,
) -> CargoResult<Requirements<'a>> {
    let mut reqs = Requirements::new(s);

    match *method {
        Method::Everything
        | Method::Required {
            all_features: true, ..
        } => {
            for key in s.features().keys() {
                reqs.require_feature(*key)?;
            }
            for dep in s.dependencies().iter().filter(|d| d.is_optional()) {
                reqs.require_dependency(dep.name_in_toml());
            }
        }
        Method::Required {
            all_features: false,
            features: requested,
            ..
        } => {
            for &f in requested.iter() {
                reqs.require_value(&FeatureValue::new(f, s))?;
            }
        }
    }
    match *method {
        Method::Everything
        | Method::Required {
            uses_default_features: true,
            ..
        } => {
            if s.features().contains_key("default") {
                reqs.require_feature(InternedString::new("default"))?;
            }
        }
        Method::Required {
            uses_default_features: false,
            ..
        } => {}
    }
    Ok(reqs)
}

struct Requirements<'a> {
    summary: &'a Summary,
    // The deps map is a mapping of package name to list of features enabled.
    // Each package should be enabled, and each package should have the
    // specified set of features enabled. The boolean indicates whether this
    // package was specifically requested (rather than just requesting features
    // *within* this package).
    deps: HashMap<InternedString, (bool, Vec<InternedString>)>,
    // The used features set is the set of features which this local package had
    // enabled, which is later used when compiling to instruct the code what
    // features were enabled.
    used: HashSet<InternedString>,
    visited: HashSet<InternedString>,
}

impl<'r> Requirements<'r> {
    fn new(summary: &Summary) -> Requirements<'_> {
        Requirements {
            summary,
            deps: HashMap::new(),
            used: HashSet::new(),
            visited: HashSet::new(),
        }
    }

    fn require_crate_feature(&mut self, package: InternedString, feat: InternedString) {
        self.used.insert(package);
        self.deps
            .entry(package)
            .or_insert((false, Vec::new()))
            .1
            .push(feat);
    }

    fn seen(&mut self, feat: InternedString) -> bool {
        if self.visited.insert(feat) {
            self.used.insert(feat);
            false
        } else {
            true
        }
    }

    fn require_dependency(&mut self, pkg: InternedString) {
        if self.seen(pkg) {
            return;
        }
        self.deps.entry(pkg).or_insert((false, Vec::new())).0 = true;
    }

    fn require_feature(&mut self, feat: InternedString) -> CargoResult<()> {
        if feat.is_empty() || self.seen(feat) {
            return Ok(());
        }
        for fv in self
            .summary
            .features()
            .get(feat.as_str())
            .expect("must be a valid feature")
        {
            match *fv {
                FeatureValue::Feature(ref dep_feat) if **dep_feat == *feat => failure::bail!(
                    "Cyclic feature dependency: feature `{}` depends on itself",
                    feat
                ),
                _ => {}
            }
            self.require_value(fv)?;
        }
        Ok(())
    }

    fn require_value<'f>(&mut self, fv: &'f FeatureValue) -> CargoResult<()> {
        match fv {
            FeatureValue::Feature(feat) => self.require_feature(*feat)?,
            FeatureValue::Crate(dep) => self.require_dependency(*dep),
            FeatureValue::CrateFeature(dep, dep_feat) => {
                self.require_crate_feature(*dep, *dep_feat)
            }
        };
        Ok(())
    }
}
<commit_msg>Auto merge of #6510 - d-e-s-o:add-missing-noun, r=dwijnand<commit_after>use std::collections::{BTreeMap, HashMap, HashSet};
use std::rc::Rc;

#[allow(unused_imports)] // "ensure" seems to require "bail" be in scope (macro hygiene issue?)
use failure::{bail, ensure};
use log::debug;

use crate::core::interning::InternedString;
use crate::core::{Dependency, FeatureValue, PackageId, SourceId, Summary};
use crate::util::CargoResult;
use crate::util::Graph;

use super::errors::ActivateResult;
use super::types::{ConflictReason, DepInfo, GraphNode, Method, RcList, RegistryQueryer};

pub use super::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
pub use super::encode::{Metadata, WorkspaceResolve};
pub use super::resolve::Resolve;

// A `Context` is basically a bunch of local resolution information which is
// kept around for all `BacktrackFrame` instances. As a result, this runs the
// risk of being cloned *a lot* so we want to make this as cheap to clone as
// possible.
#[derive(Clone)]
pub struct Context {
    pub activations: Activations,
    pub resolve_features: im_rc::HashMap<PackageId, Rc<HashSet<InternedString>>>,
    pub links: im_rc::HashMap<InternedString, PackageId>,

    // These are two cheaply-cloneable lists (O(1) clone) which are effectively
    // hash maps but are built up as "construction lists". We'll iterate these
    // at the very end and actually construct the map that we're making.
    pub resolve_graph: RcList<GraphNode>,
    pub resolve_replacements: RcList<(PackageId, PackageId)>,

    // These warnings are printed after resolution.
    pub warnings: RcList<String>,
}

pub type Activations = im_rc::HashMap<(InternedString, SourceId), Rc<Vec<Summary>>>;

impl Context {
    pub fn new() -> Context {
        Context {
            resolve_graph: RcList::new(),
            resolve_features: im_rc::HashMap::new(),
            links: im_rc::HashMap::new(),
            resolve_replacements: RcList::new(),
            activations: im_rc::HashMap::new(),
            warnings: RcList::new(),
        }
    }

    /// Activate this summary by inserting it into our list of known activations.
    ///
    /// Returns true if this summary with the given method is already activated.
    pub fn flag_activated(&mut self, summary: &Summary, method: &Method<'_>) -> CargoResult<bool> {
        let id = summary.package_id();
        let prev = self
            .activations
            .entry((id.name(), id.source_id()))
            .or_insert_with(|| Rc::new(Vec::new()));
        if !prev.iter().any(|c| c == summary) {
            self.resolve_graph.push(GraphNode::Add(id));
            if let Some(link) = summary.links() {
                ensure!(
                    self.links.insert(link, id).is_none(),
                    "Attempting to resolve a dependency with more then one crate with the \
                     links={}.\nThis will not build as is. Consider rebuilding the .lock file.",
                    &*link
                );
            }
            Rc::make_mut(prev).push(summary.clone());
            return Ok(false);
        }
        debug!("checking if {} is already activated", summary.package_id());
        let (features, use_default) = match *method {
            Method::Everything
            | Method::Required {
                all_features: true, ..
            } => return Ok(false),
            Method::Required {
                features,
                uses_default_features,
                ..
            } => (features, uses_default_features),
        };

        let has_default_feature = summary.features().contains_key("default");
        Ok(match self.resolve_features.get(&id) {
            Some(prev) => {
                features.iter().all(|f| prev.contains(f))
                    && (!use_default || prev.contains("default") || !has_default_feature)
            }
            None => features.is_empty() && (!use_default || !has_default_feature),
        })
    }

    pub fn build_deps(
        &mut self,
        registry: &mut RegistryQueryer<'_>,
        parent: Option<&Summary>,
        candidate: &Summary,
        method: &Method<'_>,
    ) -> ActivateResult<Vec<DepInfo>> {
        // First, figure out our set of dependencies based on the requested set
        // of features. This also calculates what features we're going to enable
        // for our own dependencies.
        let deps = self.resolve_features(parent, candidate, method)?;

        // Next, transform all dependencies into a list of possible candidates
        // which can satisfy that dependency.
        let mut deps = deps
            .into_iter()
            .map(|(dep, features)| {
                let candidates = registry.query(&dep)?;
                Ok((dep, candidates, Rc::new(features)))
            })
            .collect::<CargoResult<Vec<DepInfo>>>()?;

        // Attempt to resolve dependencies with fewer candidates before trying
        // dependencies with more candidates.  This way if the dependency with
        // only one candidate can't be resolved we don't have to do a bunch of
        // work before we figure that out.
        deps.sort_by_key(|&(_, ref a, _)| a.len());

        Ok(deps)
    }

    pub fn prev_active(&self, dep: &Dependency) -> &[Summary] {
        self.activations
            .get(&(dep.package_name(), dep.source_id()))
            .map(|v| &v[..])
            .unwrap_or(&[])
    }

    pub fn is_active(&self, id: PackageId) -> bool {
        self.activations
            .get(&(id.name(), id.source_id()))
            .map(|v| v.iter().any(|s| s.package_id() == id))
            .unwrap_or(false)
    }

    /// checks whether all of `parent` and the keys of `conflicting activations`
    /// are still active
    pub fn is_conflicting(
        &self,
        parent: Option<PackageId>,
        conflicting_activations: &BTreeMap<PackageId, ConflictReason>,
    ) -> bool {
        conflicting_activations
            .keys()
            .chain(parent.as_ref())
            .all(|&id| self.is_active(id))
    }

    /// Return all dependencies and the features we want from them.
    fn resolve_features<'b>(
        &mut self,
        parent: Option<&Summary>,
        s: &'b Summary,
        method: &'b Method<'_>,
    ) -> ActivateResult<Vec<(Dependency, Vec<InternedString>)>> {
        let dev_deps = match *method {
            Method::Everything => true,
            Method::Required { dev_deps, .. } => dev_deps,
        };

        // First, filter by dev-dependencies
        let deps = s.dependencies();
        let deps = deps.iter().filter(|d| d.is_transitive() || dev_deps);

        let reqs = build_requirements(s, method)?;
        let mut ret = Vec::new();
        let mut used_features = HashSet::new();
        let default_dep = (false, Vec::new());

        // Next, collect all actually enabled dependencies and their features.
        for dep in deps {
            // Skip optional dependencies, but not those enabled through a
            // feature
            if dep.is_optional() && !reqs.deps.contains_key(&dep.name_in_toml()) {
                continue;
            }
            // So we want this dependency. Move the features we want from
            // `feature_deps` to `ret` and register ourselves as using this
            // name.
            let base = reqs.deps.get(&dep.name_in_toml()).unwrap_or(&default_dep);
            used_features.insert(dep.name_in_toml());
            let always_required = !dep.is_optional()
                && !s
                    .dependencies()
                    .iter()
                    .any(|d| d.is_optional() && d.name_in_toml() == dep.name_in_toml());
            if always_required && base.0 {
                self.warnings.push(format!(
                    "Package `{}` does not have feature `{}`. It has a required dependency \
                     with that name, but only optional dependencies can be used as features. \
                     This is currently a warning to ease the transition, but it will become an \
                     error in the future.",
                    s.package_id(),
                    dep.name_in_toml()
                ));
            }
            let mut base = base.1.clone();
            base.extend(dep.features().iter());
            for feature in base.iter() {
                if feature.contains('/') {
                    return Err(failure::format_err!(
                        "feature names may not contain slashes: `{}`",
                        feature
                    )
                    .into());
                }
            }
            ret.push((dep.clone(), base));
        }

        // Any entries in `reqs.dep` which weren't used are bugs in that the
        // package does not actually have those dependencies. We classified
        // them as dependencies in the first place because there is no such
        // feature, either.
        let remaining = reqs
            .deps
            .keys()
            .cloned()
            .filter(|s| !used_features.contains(s))
            .collect::<Vec<_>>();
        if !remaining.is_empty() {
            let features = remaining.join(", ");
            return Err(match parent {
                None => failure::format_err!(
                    "Package `{}` does not have these features: `{}`",
                    s.package_id(),
                    features
                )
                .into(),
                Some(p) => (p.package_id(), ConflictReason::MissingFeatures(features)).into(),
            });
        }

        // Record what list of features is active for this package.
        if !reqs.used.is_empty() {
            let pkgid = s.package_id();

            let set = Rc::make_mut(
                self.resolve_features
                    .entry(pkgid)
                    .or_insert_with(|| Rc::new(HashSet::new())),
            );

            for feature in reqs.used {
                set.insert(feature);
            }
        }

        Ok(ret)
    }

    pub fn resolve_replacements(&self) -> HashMap<PackageId, PackageId> {
        let mut replacements = HashMap::new();
        let mut cur = &self.resolve_replacements;
        while let Some(ref node) = cur.head {
            let (k, v) = node.0;
            replacements.insert(k, v);
            cur = &node.1;
        }
        replacements
    }

    pub fn graph(&self) -> Graph<PackageId, Vec<Dependency>> {
        let mut graph: Graph<PackageId, Vec<Dependency>> = Graph::new();
        let mut cur = &self.resolve_graph;
        while let Some(ref node) = cur.head {
            match node.0 {
                GraphNode::Add(ref p) => graph.add(p.clone()),
                GraphNode::Link(ref a, ref b, ref dep) => {
                    graph.link(a.clone(), b.clone()).push(dep.clone());
                }
            }
            cur = &node.1;
        }
        graph
    }
}

/// Takes requested features for a single package from the input Method and
/// recurses to find all requested features, dependencies and requested
/// dependency features in a Requirements object, returning it to the resolver.
fn build_requirements<'a, 'b: 'a>(
    s: &'a Summary,
    method: &'b Method<'_>,
) -> CargoResult<Requirements<'a>> {
    let mut reqs = Requirements::new(s);

    match *method {
        Method::Everything
        | Method::Required {
            all_features: true, ..
        } => {
            for key in s.features().keys() {
                reqs.require_feature(*key)?;
            }
            for dep in s.dependencies().iter().filter(|d| d.is_optional()) {
                reqs.require_dependency(dep.name_in_toml());
            }
        }
        Method::Required {
            all_features: false,
            features: requested,
            ..
        } => {
            for &f in requested.iter() {
                reqs.require_value(&FeatureValue::new(f, s))?;
            }
        }
    }
    match *method {
        Method::Everything
        | Method::Required {
            uses_default_features: true,
            ..
        } => {
            if s.features().contains_key("default") {
                reqs.require_feature(InternedString::new("default"))?;
            }
        }
        Method::Required {
            uses_default_features: false,
            ..
        } => {}
    }
    Ok(reqs)
}

struct Requirements<'a> {
    summary: &'a Summary,
    // The deps map is a mapping of package name to list of features enabled.
    // Each package should be enabled, and each package should have the
    // specified set of features enabled. The boolean indicates whether this
    // package was specifically requested (rather than just requesting features
    // *within* this package).
    deps: HashMap<InternedString, (bool, Vec<InternedString>)>,
    // The used features set is the set of features which this local package had
    // enabled, which is later used when compiling to instruct the code what
    // features were enabled.
    used: HashSet<InternedString>,
    visited: HashSet<InternedString>,
}

impl<'r> Requirements<'r> {
    fn new(summary: &Summary) -> Requirements<'_> {
        Requirements {
            summary,
            deps: HashMap::new(),
            used: HashSet::new(),
            visited: HashSet::new(),
        }
    }

    fn require_crate_feature(&mut self, package: InternedString, feat: InternedString) {
        self.used.insert(package);
        self.deps
            .entry(package)
            .or_insert((false, Vec::new()))
            .1
            .push(feat);
    }

    fn seen(&mut self, feat: InternedString) -> bool {
        if self.visited.insert(feat) {
            self.used.insert(feat);
            false
        } else {
            true
        }
    }

    fn require_dependency(&mut self, pkg: InternedString) {
        if self.seen(pkg) {
            return;
        }
        self.deps.entry(pkg).or_insert((false, Vec::new())).0 = true;
    }

    fn require_feature(&mut self, feat: InternedString) -> CargoResult<()> {
        if feat.is_empty() || self.seen(feat) {
            return Ok(());
        }
        for fv in self
            .summary
            .features()
            .get(feat.as_str())
            .expect("must be a valid feature")
        {
            match *fv {
                FeatureValue::Feature(ref dep_feat) if **dep_feat == *feat => failure::bail!(
                    "Cyclic feature dependency: feature `{}` depends on itself",
                    feat
                ),
                _ => {}
            }
            self.require_value(fv)?;
        }
        Ok(())
    }

    fn require_value<'f>(&mut self, fv: &'f FeatureValue) -> CargoResult<()> {
        match fv {
            FeatureValue::Feature(feat) => self.require_feature(*feat)?,
            FeatureValue::Crate(dep) => self.require_dependency(*dep),
            FeatureValue::CrateFeature(dep, dep_feat) => {
                self.require_crate_feature(*dep, *dep_feat)
            }
        };
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! The distrib module provides methods for executing the rendering in a
//! distributed environment across multiple machies. The worker module provides
//! the Worker which does the actual job of rendering a subregion of the image.
//! The master module provides the Master which instructs the Workers what to render
//! and collects their results to save out the final image.
//!
//! # Usage
//!
//! The worker process takes very few arguments, just a flag indicating it's a worker
//! and optionally the number of threads to use with `-n`.
//!
//! ```
//! ./tray_rust --worker
//! ```
//!
//! The worker processes will listen on a hard-coded port for the master to send them instructions
//! about what parts of the image they should render. This is `exec::distrib::worker::PORT` which
//! you can change and re-compile if the default of 63234 conflicts with other applications.
//!
//! The master process can be run on the same machine as a worker since it doesn't take
//! up too much CPU time. To run the master you'll pass it the scene file, a list of the
//! worker hostnames or IP addresses and optionally an output path and start/end frame numbers.
//! You can also run tray\_rust with the `-h` or `--help` flag to see a list of options.
//!
//! ```
//! ./tray_rust cornell_box.json --master worker1 worker2 192.168.32.129
//! ```
//!
//! The master will send the workers the location of the scene file which is assumed to
//! be on some shared filesystem or otherwise available at the same path on all the workers.
//!
//! # Running on GCE or EC2
//!
//! You can run on any network of home machines but you can also run on virtual machines from
//! Google or Amazon if you want to rent a mini cluster. On GCE or EC2 you'll want machines in the
//! same region for faster communication and will then pass the local IPs of the workers to
//! the master. For example on GCE you're given a virtual local network, you would use
//! these IP addresses instead of the public IPs of the worker nodes.
//!

use bincode::rustc_serialize::encoded_size;

pub use self::worker::Worker;
pub use self::master::Master;

pub mod worker;
pub mod master;

/// Stores instructions sent to a worker about which blocks it should be rendering,
/// block size is assumed to be 8x8
#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
struct Instructions {
    /// Size header for binary I/O with bincode
    pub encoded_size: u64,
    /// Scene file for the worker to load
    pub scene: String,
    /// Frames to be rendered (inclusive)
    pub frames: (usize, usize),
    /// Block in the z-order queue of blocks this worker will
    /// start at
    pub block_start: usize,
    /// Number of blocks this worker will render
    pub block_count: usize,
}

impl Instructions {
    pub fn new(scene: &String, frames: (usize, usize), block_start: usize,
               block_count: usize) -> Instructions {
        let mut instr = Instructions { encoded_size: 0, scene: scene.clone(), frames: frames,
                       block_start: block_start, block_count: block_count };
        instr.encoded_size = encoded_size(&instr);
        instr
    }
}

/// Frame is used by the worker to send its results back to the master. Sends information
/// about which frame is being sent, which blocks were rendered and the data for the blocks
#[derive(RustcEncodable, RustcDecodable)]
struct Frame {
    /// Size header for binary I/O with bincode
    pub encoded_size: u64,
    /// Which frame the worker is sending its results for
    pub frame: usize,
    /// Block size of the blocks being sent
    pub block_size: (usize, usize),
    /// Starting locations of each block
    pub blocks: Vec<(usize, usize)>,
    /// Sample data for each block, RGBW_F32 (W = weight)
    pub pixels: Vec<f32>,
}

impl Frame {
    pub fn new(frame: usize, block_size: (usize, usize), blocks: Vec<(usize, usize)>,
               pixels: Vec<f32>) -> Frame {
        let mut frame = Frame { encoded_size: 0, frame: frame, block_size: block_size,
                            blocks: blocks, pixels: pixels };
        frame.encoded_size = encoded_size(&frame);
        frame
    }
}

<commit_msg>Forgot about doc tests being run, mark correctly as text<commit_after>//! The distrib module provides methods for executing the rendering in a
//! distributed environment across multiple machies. The worker module provides
//! the Worker which does the actual job of rendering a subregion of the image.
//! The master module provides the Master which instructs the Workers what to render
//! and collects their results to save out the final image.
//!
//! # Usage
//!
//! The worker process takes very few arguments, just a flag indicating it's a worker
//! and optionally the number of threads to use with `-n`.
//!
//! ```text
//! ./tray_rust --worker
//! ```
//!
//! The worker processes will listen on a hard-coded port for the master to send them instructions
//! about what parts of the image they should render. This is `exec::distrib::worker::PORT` which
//! you can change and re-compile if the default of 63234 conflicts with other applications.
//!
//! The master process can be run on the same machine as a worker since it doesn't take
//! up too much CPU time. To run the master you'll pass it the scene file, a list of the
//! worker hostnames or IP addresses and optionally an output path and start/end frame numbers.
//! You can also run tray\_rust with the `-h` or `--help` flag to see a list of options.
//!
//! ```text
//! ./tray_rust cornell_box.json --master worker1 worker2 192.168.32.129
//! ```
//!
//! The master will send the workers the location of the scene file which is assumed to
//! be on some shared filesystem or otherwise available at the same path on all the workers.
//!
//! # Running on GCE or EC2
//!
//! You can run on any network of home machines but you can also run on virtual machines from
//! Google or Amazon if you want to rent a mini cluster. On GCE or EC2 you'll want machines in the
//! same region for faster communication and will then pass the local IPs of the workers to
//! the master. For example on GCE you're given a virtual local network, you would use
//! these IP addresses instead of the public IPs of the worker nodes.
//!

use bincode::rustc_serialize::encoded_size;

pub use self::worker::Worker;
pub use self::master::Master;

pub mod worker;
pub mod master;

/// Stores instructions sent to a worker about which blocks it should be rendering,
/// block size is assumed to be 8x8
#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
struct Instructions {
    /// Size header for binary I/O with bincode
    pub encoded_size: u64,
    /// Scene file for the worker to load
    pub scene: String,
    /// Frames to be rendered (inclusive)
    pub frames: (usize, usize),
    /// Block in the z-order queue of blocks this worker will
    /// start at
    pub block_start: usize,
    /// Number of blocks this worker will render
    pub block_count: usize,
}

impl Instructions {
    pub fn new(scene: &String, frames: (usize, usize), block_start: usize,
               block_count: usize) -> Instructions {
        let mut instr = Instructions { encoded_size: 0, scene: scene.clone(), frames: frames,
                       block_start: block_start, block_count: block_count };
        instr.encoded_size = encoded_size(&instr);
        instr
    }
}

/// Frame is used by the worker to send its results back to the master. Sends information
/// about which frame is being sent, which blocks were rendered and the data for the blocks
#[derive(RustcEncodable, RustcDecodable)]
struct Frame {
    /// Size header for binary I/O with bincode
    pub encoded_size: u64,
    /// Which frame the worker is sending its results for
    pub frame: usize,
    /// Block size of the blocks being sent
    pub block_size: (usize, usize),
    /// Starting locations of each block
    pub blocks: Vec<(usize, usize)>,
    /// Sample data for each block, RGBW_F32 (W = weight)
    pub pixels: Vec<f32>,
}

impl Frame {
    pub fn new(frame: usize, block_size: (usize, usize), blocks: Vec<(usize, usize)>,
               pixels: Vec<f32>) -> Frame {
        let mut frame = Frame { encoded_size: 0, frame: frame, block_size: block_size,
                            blocks: blocks, pixels: pixels };
        frame.encoded_size = encoded_size(&frame);
        frame
    }
}

<|endoftext|>


<commit_before>/// `ExpectedVersion` represents the different modes of optimistic locking when writing to a stream
/// using `WriteEventsBuilder`.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ExpectedVersion {
    /// No optimistic locking
    Any,
    /// Expect a stream not to exist
    NoStream,
    /// Expect exact number of events in the stream
    Exact(u32)
}

impl From<ExpectedVersion> for i32 {
    /// Returns the wire representation.
    fn from(version: ExpectedVersion) -> Self {
        use self::ExpectedVersion::*;
        match version {
            Any => -2,
            NoStream => -1,
            Exact(ver) => ver as i32
        }
    }
}
<commit_msg>expected-version: Use a StreamVersion instead of a raw u32<commit_after>use StreamVersion;

/// `ExpectedVersion` represents the different modes of optimistic locking when writing to a stream
/// using `WriteEventsBuilder`.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ExpectedVersion {
    /// No optimistic locking
    Any,
    /// Expect a stream not to exist
    NoStream,
    /// Expect exact number of events in the stream
    Exact(StreamVersion)
}

impl From<ExpectedVersion> for i32 {
    /// Returns the wire representation.
    fn from(version: ExpectedVersion) -> Self {
        use self::ExpectedVersion::*;
        match version {
            Any => -2,
            NoStream => -1,
            Exact(ver) => ver.into()
        }
    }
}
<|endoftext|>


<commit_before>use game::board::{GoBoard, GoMove, State};

struct Group {
    indicies: Vec<usize>,
    liberties: i8,
    owner: State,
}

// A very simple GoBoard implementation where little attempt is made to optimize space and
// time complexities.
pub struct SimpleBoard {
    pub intersections: Vec<State>,
    groups: Vec<Group>,
    xsize: i8,
    ysize: i8,
}

impl GoBoard for SimpleBoard {
    fn new(ysize: i8, xsize: i8) -> SimpleBoard {
        SimpleBoard {
            intersections: vec![State::Empty; ((xsize as i32)*(ysize as i32)) as usize],
            groups: Vec::new(),
            xsize: xsize,
            ysize: ysize
        }
    }

    fn play_move(&mut self, mv: GoMove) {
        match mv {
            GoMove::Move {x, y, player} => self.play_at_coordinates(x, y, player),
            GoMove::Pass => {},
        };
    }
}

impl SimpleBoard {
    fn play_at_coordinates(&mut self, x: i8, y: i8, player: State) {
        // First check if there is already a stone here
        let index = self.coordinates_to_index(x, y);
        if self.intersections[index.unwrap()] != State::Empty {
            // not a valid move
        }
        else {
            // If our move was valid, add it to the board
            self.intersections[index.unwrap()] = player;
            let neighbors = self.neighbor_indicies(x, y);
            // Update the neighboring groups if there are any
            let mut group_indicies: Vec<usize> = Vec::new();
            let mut num_neighbors: i8 = 0;
            for neighbor in neighbors.iter() {
                match *neighbor {
                    Some(x) => {
                        let group_index = self.group_ref(x);
                        if group_index != None {
                            group_indicies.push(group_index.unwrap());
                        }
                        num_neighbors += 1;
                    },
                    None => {},
                }
            }
            group_indicies.sort();
            group_indicies.dedup();
            let added_to_group = self.update_groups(&group_indicies, index.unwrap(), player);
            if !added_to_group {
                // There were no neighboring groups, so we have to add one
                self.groups.push(Group{
                    indicies: vec![index.unwrap(); 1],
                    liberties: num_neighbors,
                    owner: player,
                })
            }
        }
    }

    fn group_ref(&mut self, index: usize) -> Option<usize> {
        let mut ret: Option<usize> = None;
        for (i, group) in self.groups.iter().enumerate() {
            if group.indicies.contains(&index) {
                ret = Some(i);
            }
        }
        ret
    }

    fn update_groups(&mut self, group_indicies: &Vec<usize>, play_index: usize, player: State) -> bool {
        let mut groups_to_merge: Vec<usize> = Vec::new();
        let mut added_to_group = false;
        for i in group_indicies.iter() {
            if self.groups[*i].owner == player {
                // Add the stone to the group
                self.groups[*i].indicies.push(play_index);
                groups_to_merge.push(*i);
                added_to_group = true;
            }
            else {
                // Attaching to an enemy group, this will reduce liberties by 1
                self.groups[*i].liberties -= 1;
            }
        }

        if groups_to_merge.len() > 1 {
            // We have friendly groups that the played stone merged together
            // group indices is already sorted so loop in reverse order, ignoring the
            // first group element
            for (i, gidx) in groups_to_merge.iter().rev().enumerate() {
                if i != 0 {
                    let other_group_copy: Vec<usize> = self.groups[*gidx].indicies.clone();
                    self.groups[groups_to_merge[0]].indicies.extend_from_slice(other_group_copy.as_slice());
                    self.groups.remove(*gidx);
                }
            }
        }
        // Kill off any groups that were killed by playing the immediate stone
        self.remove_all_dead_groups();
        // Recalculate all liberties
        self.recalculate_liberties();
        added_to_group
    }

    fn recalculate_liberties(&mut self) {
        let mut new_liberties: Vec<i8> = Vec::new();
        for group in &self.groups {
            let mut liberties: i8 = 0;
            let mut all_neighbors: Vec<Option<usize>> = Vec::new();
            for stone in &group.indicies {
                let (x, y) = self.index_to_coordinates(*stone);
                let neighbor = self.neighbor_indicies(x, y);

                all_neighbors.extend_from_slice(&neighbor);
            }
            all_neighbors.sort();
            all_neighbors.dedup();
            for n in all_neighbors.iter() {
                match *n {
                    Some(x) => {
                        if self.intersections[x] == State::Empty {
                            liberties += 1;
                        }
                    }
                    None => {},
                }
            }
            new_liberties.push(liberties);
        }
        for (i, l) in new_liberties.iter().enumerate() {
            self.groups[i].liberties = *l;
        }
    }

    fn remove_all_dead_groups(&mut self) {
        // Remove all groups with 0 liberties
        let mut groups_to_kill: Vec<usize> = Vec::new();
        for (i, group) in self.groups.iter().enumerate() {
            if group.liberties == 0 {
                groups_to_kill.push(i);
            }
        }
        // Group indicies will already be sorted, so iterate in reverse order and remove
        // them from the board
        for i in groups_to_kill.iter().rev() {
            self.remove_group(*i);
        }
    }

    fn remove_group(&mut self, group_index: usize) {
        for index in self.groups[group_index].indicies.iter() {
            self.intersections[*index] = State::Empty;
        }
        self.groups.remove(group_index);
    }

    fn neighbor_indicies(&self, x: i8, y: i8) -> [Option<usize>; 4] {
        [self.coordinates_to_index(x-1, y),
         self.coordinates_to_index(x+1, y),
         self.coordinates_to_index(x, y-1),
         self.coordinates_to_index(x, y+1)]
    }

    fn coordinates_to_index(&self, x: i8, y: i8) -> Option<usize> {
        let index: i32 = ((x as i32) + (y as i32)*(self.xsize as i32)) as i32;
        if index < 0 || index >= (self.xsize as i32)*(self.ysize as i32) {
            None
        }
        else {
            Some(((x as i32) + (y as i32)*(self.xsize as i32)) as usize)
        }
    }

    fn index_to_coordinates(&self, index: usize) -> (i8, i8) {
        let x = (index % (self.xsize as usize)) as i8;
        let y = (index / (self.xsize as usize)) as i8;
        (x, y)
    }

    pub fn print_board(&self) {
        // upper boundary
        // println!("{}", iter::repeat("_").take(10).collect::<String>());

        for y in 0..self.ysize {
            for x in 0..self.xsize {
                let index = (x + y*self.xsize) as usize;
                print!("|{:?}", self.intersections[index]);
            }
            println!("|", );
        }

        // lower boundary
        // println!("{}", iter::repeat("_").take(10).collect::<String>());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use game::board::*;

    #[test]
    fn play_move() {
        let mut game_board = SimpleBoard::new(3, 4);
        let mv = GoMove::Move{x: 2, y: 2, player: State::White};
        game_board.play_move(mv);
    }

    #[test]
    #[should_panic]
    fn play_move_out_of_bounds() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv = GoMove::Move{x: 3, y: 3, player: State::White};
        game_board.play_move(mv);
    }

    #[test]
    fn corner_capture() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv1 = GoMove::Move{ x: 0, y: 0, player: State::White};
        let mv2 = GoMove::Move{ x: 0, y: 1, player: State::Black};
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black};

        game_board.play_move(mv1);
        game_board.play_move(mv2);
        game_board.play_move(mv3);

        assert_eq!(State::Empty, game_board.intersections[0]);
        assert_eq!(State::Black, game_board.intersections[1]);
        assert_eq!(State::Black, game_board.intersections[3]);
    }

    #[test]
    fn pass() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv = GoMove::Pass;
        game_board.play_move(mv);
    }

    #[test]
    fn merge_groups() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv1 = GoMove::Move{ x: 0, y: 0, player: State::Black};
        let mv2 = GoMove::Move{ x: 2, y: 0, player: State::Black};
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black};

        game_board.play_move(mv1);
        game_board.play_move(mv2);

        assert_eq!(game_board.groups.len(), 2);

        game_board.play_move(mv3);

        assert_eq!(game_board.groups.len(), 1);
    }

    #[test]
    fn capture_with_one_eye() {
        let mut game_board = SimpleBoard::new(2, 2);
        let mv1 = GoMove::Move{ x: 0, y: 1, player: State::Black };
        let mv2 = GoMove::Move{ x: 1, y: 1, player: State::Black };
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black };

        game_board.play_move(mv1);
        game_board.play_move(mv2);
        game_board.play_move(mv3);

        let mv4 = GoMove::Move{ x: 0, y: 0, player: State::White };

        game_board.play_move(mv4);

        assert_eq!(State::White, game_board.intersections[0]);
        assert_eq!(State::Empty, game_board.intersections[1]);
        assert_eq!(State::Empty, game_board.intersections[2]);
        assert_eq!(State::Empty, game_board.intersections[3]);

        assert_eq!(game_board.groups.len(), 1);

        assert_eq!(game_board.groups[0].liberties, 2);
    }
}
<commit_msg>Group and SimpleBoard now derive Clone<commit_after>use game::board::{GoBoard, GoMove, State};

#[derive(Clone)]
struct Group {
    indicies: Vec<usize>,
    liberties: i8,
    owner: State,
}

// A very simple GoBoard implementation where little attempt is made to optimize space and
// time complexities.
#[derive(Clone)]
pub struct SimpleBoard {
    pub intersections: Vec<State>,
    groups: Vec<Group>,
    xsize: i8,
    ysize: i8,
}

impl GoBoard for SimpleBoard {
    fn new(ysize: i8, xsize: i8) -> SimpleBoard {
        SimpleBoard {
            intersections: vec![State::Empty; ((xsize as i32)*(ysize as i32)) as usize],
            groups: Vec::new(),
            xsize: xsize,
            ysize: ysize
        }
    }

    fn play_move(&mut self, mv: GoMove) {
        match mv {
            GoMove::Move {x, y, player} => self.play_at_coordinates(x, y, player),
            GoMove::Pass => {},
        };
    }
}

impl SimpleBoard {
    fn play_at_coordinates(&mut self, x: i8, y: i8, player: State) {
        // First check if there is already a stone here
        let index = self.coordinates_to_index(x, y);
        if self.intersections[index.unwrap()] != State::Empty {
            // not a valid move
        }
        else {
            // If our move was valid, add it to the board
            self.intersections[index.unwrap()] = player;
            let neighbors = self.neighbor_indicies(x, y);
            // Update the neighboring groups if there are any
            let mut group_indicies: Vec<usize> = Vec::new();
            let mut num_neighbors: i8 = 0;
            for neighbor in neighbors.iter() {
                match *neighbor {
                    Some(x) => {
                        let group_index = self.group_ref(x);
                        if group_index != None {
                            group_indicies.push(group_index.unwrap());
                        }
                        num_neighbors += 1;
                    },
                    None => {},
                }
            }
            group_indicies.sort();
            group_indicies.dedup();
            let added_to_group = self.update_groups(&group_indicies, index.unwrap(), player);
            if !added_to_group {
                // There were no neighboring groups, so we have to add one
                self.groups.push(Group{
                    indicies: vec![index.unwrap(); 1],
                    liberties: num_neighbors,
                    owner: player,
                })
            }
        }
    }

    fn group_ref(&mut self, index: usize) -> Option<usize> {
        let mut ret: Option<usize> = None;
        for (i, group) in self.groups.iter().enumerate() {
            if group.indicies.contains(&index) {
                ret = Some(i);
            }
        }
        ret
    }

    fn update_groups(&mut self, group_indicies: &Vec<usize>, play_index: usize, player: State) -> bool {
        let mut groups_to_merge: Vec<usize> = Vec::new();
        let mut added_to_group = false;
        for i in group_indicies.iter() {
            if self.groups[*i].owner == player {
                // Add the stone to the group
                self.groups[*i].indicies.push(play_index);
                groups_to_merge.push(*i);
                added_to_group = true;
            }
            else {
                // Attaching to an enemy group, this will reduce liberties by 1
                self.groups[*i].liberties -= 1;
            }
        }

        if groups_to_merge.len() > 1 {
            // We have friendly groups that the played stone merged together
            // group indices is already sorted so loop in reverse order, ignoring the
            // first group element
            for (i, gidx) in groups_to_merge.iter().rev().enumerate() {
                if i != 0 {
                    let other_group_copy: Vec<usize> = self.groups[*gidx].indicies.clone();
                    self.groups[groups_to_merge[0]].indicies.extend_from_slice(other_group_copy.as_slice());
                    self.groups.remove(*gidx);
                }
            }
        }
        // Kill off any groups that were killed by playing the immediate stone
        self.remove_all_dead_groups();
        // Recalculate all liberties
        self.recalculate_liberties();
        added_to_group
    }

    fn recalculate_liberties(&mut self) {
        let mut new_liberties: Vec<i8> = Vec::new();
        for group in &self.groups {
            let mut liberties: i8 = 0;
            let mut all_neighbors: Vec<Option<usize>> = Vec::new();
            for stone in &group.indicies {
                let (x, y) = self.index_to_coordinates(*stone);
                let neighbor = self.neighbor_indicies(x, y);

                all_neighbors.extend_from_slice(&neighbor);
            }
            all_neighbors.sort();
            all_neighbors.dedup();
            for n in all_neighbors.iter() {
                match *n {
                    Some(x) => {
                        if self.intersections[x] == State::Empty {
                            liberties += 1;
                        }
                    }
                    None => {},
                }
            }
            new_liberties.push(liberties);
        }
        for (i, l) in new_liberties.iter().enumerate() {
            self.groups[i].liberties = *l;
        }
    }

    fn remove_all_dead_groups(&mut self) {
        // Remove all groups with 0 liberties
        let mut groups_to_kill: Vec<usize> = Vec::new();
        for (i, group) in self.groups.iter().enumerate() {
            if group.liberties == 0 {
                groups_to_kill.push(i);
            }
        }
        // Group indicies will already be sorted, so iterate in reverse order and remove
        // them from the board
        for i in groups_to_kill.iter().rev() {
            self.remove_group(*i);
        }
    }

    fn remove_group(&mut self, group_index: usize) {
        for index in self.groups[group_index].indicies.iter() {
            self.intersections[*index] = State::Empty;
        }
        self.groups.remove(group_index);
    }

    fn neighbor_indicies(&self, x: i8, y: i8) -> [Option<usize>; 4] {
        [self.coordinates_to_index(x-1, y),
         self.coordinates_to_index(x+1, y),
         self.coordinates_to_index(x, y-1),
         self.coordinates_to_index(x, y+1)]
    }

    fn coordinates_to_index(&self, x: i8, y: i8) -> Option<usize> {
        let index: i32 = ((x as i32) + (y as i32)*(self.xsize as i32)) as i32;
        if index < 0 || index >= (self.xsize as i32)*(self.ysize as i32) {
            None
        }
        else {
            Some(((x as i32) + (y as i32)*(self.xsize as i32)) as usize)
        }
    }

    fn index_to_coordinates(&self, index: usize) -> (i8, i8) {
        let x = (index % (self.xsize as usize)) as i8;
        let y = (index / (self.xsize as usize)) as i8;
        (x, y)
    }

    pub fn print_board(&self) {
        // upper boundary
        // println!("{}", iter::repeat("_").take(10).collect::<String>());

        for y in 0..self.ysize {
            for x in 0..self.xsize {
                let index = (x + y*self.xsize) as usize;
                print!("|{:?}", self.intersections[index]);
            }
            println!("|", );
        }

        // lower boundary
        // println!("{}", iter::repeat("_").take(10).collect::<String>());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use game::board::*;

    #[test]
    fn play_move() {
        let mut game_board = SimpleBoard::new(3, 4);
        let mv = GoMove::Move{x: 2, y: 2, player: State::White};
        game_board.play_move(mv);
    }

    #[test]
    #[should_panic]
    fn play_move_out_of_bounds() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv = GoMove::Move{x: 3, y: 3, player: State::White};
        game_board.play_move(mv);
    }

    #[test]
    fn corner_capture() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv1 = GoMove::Move{ x: 0, y: 0, player: State::White};
        let mv2 = GoMove::Move{ x: 0, y: 1, player: State::Black};
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black};

        game_board.play_move(mv1);
        game_board.play_move(mv2);
        game_board.play_move(mv3);

        assert_eq!(State::Empty, game_board.intersections[0]);
        assert_eq!(State::Black, game_board.intersections[1]);
        assert_eq!(State::Black, game_board.intersections[3]);
    }

    #[test]
    fn pass() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv = GoMove::Pass;
        game_board.play_move(mv);
    }

    #[test]
    fn merge_groups() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv1 = GoMove::Move{ x: 0, y: 0, player: State::Black};
        let mv2 = GoMove::Move{ x: 2, y: 0, player: State::Black};
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black};

        game_board.play_move(mv1);
        game_board.play_move(mv2);

        assert_eq!(game_board.groups.len(), 2);

        game_board.play_move(mv3);

        assert_eq!(game_board.groups.len(), 1);
    }

    #[test]
    fn capture_with_one_eye() {
        let mut game_board = SimpleBoard::new(2, 2);
        let mv1 = GoMove::Move{ x: 0, y: 1, player: State::Black };
        let mv2 = GoMove::Move{ x: 1, y: 1, player: State::Black };
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black };

        game_board.play_move(mv1);
        game_board.play_move(mv2);
        game_board.play_move(mv3);

        let mv4 = GoMove::Move{ x: 0, y: 0, player: State::White };

        game_board.play_move(mv4);

        assert_eq!(State::White, game_board.intersections[0]);
        assert_eq!(State::Empty, game_board.intersections[1]);
        assert_eq!(State::Empty, game_board.intersections[2]);
        assert_eq!(State::Empty, game_board.intersections[3]);

        assert_eq!(game_board.groups.len(), 1);

        assert_eq!(game_board.groups[0].liberties, 2);
    }
}
<|endoftext|>


<commit_before>/// The Toml Insert extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use error::*;

pub trait TomlValueInsertExt<'doc> {

    /// Extension function for inserting a value in the current toml::Value document
    /// using a custom seperator.
    ///
    /// For difference to TomlSetExt::set() and friends, read [#semantics].
    ///
    /// # Semantics
    ///
    /// The function automatically creates intermediate data structures based on the query string.
    /// That means, if the query string is `"a.b.c.[0]"`, but only a table `"a"` exists in the
    /// document, the function automatically creates a table `"b"` inside `"a"` and `"c"` inside
    /// `"b"`, and an array in `"c"`. The array index is ignored if the array is created.
    ///
    /// If an Array exists, but the specified index is larger than the last index, the array will
    /// be expanded by one element: If the array has a length of 3, but the query string specifies
    /// that the element should be put at 1000, the function ignores the large index and simply
    /// appends the value to the index.
    ///
    /// # Return value
    ///
    /// If the insert operation worked correctly, `Ok(None)` is returned.
    /// If the insert operation replaced an existing value `Ok(Some(old_value))` is returned
    /// On failure, `Err(e)` is returned
    ///
    fn insert_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>>;

    /// Extension function for inserting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueinsertExt::insert_with_seperator`
    fn insert(&mut self, query: &String, value: Value) -> Result<Option<Value>> {
        self.insert_with_seperator(query, '.', value)
    }

}

impl<'doc> TomlValueInsertExt<'doc> for Value {

    fn insert_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>> {
        use resolver::mut_resolver::resolve;

        unimplemented!()
    }

}

<commit_msg>Add simple insert tests<commit_after>/// The Toml Insert extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use error::*;

pub trait TomlValueInsertExt<'doc> {

    /// Extension function for inserting a value in the current toml::Value document
    /// using a custom seperator.
    ///
    /// For difference to TomlSetExt::set() and friends, read [#semantics].
    ///
    /// # Semantics
    ///
    /// The function automatically creates intermediate data structures based on the query string.
    /// That means, if the query string is `"a.b.c.[0]"`, but only a table `"a"` exists in the
    /// document, the function automatically creates a table `"b"` inside `"a"` and `"c"` inside
    /// `"b"`, and an array in `"c"`. The array index is ignored if the array is created.
    ///
    /// If an Array exists, but the specified index is larger than the last index, the array will
    /// be expanded by one element: If the array has a length of 3, but the query string specifies
    /// that the element should be put at 1000, the function ignores the large index and simply
    /// appends the value to the index.
    ///
    /// # Return value
    ///
    /// If the insert operation worked correctly, `Ok(None)` is returned.
    /// If the insert operation replaced an existing value `Ok(Some(old_value))` is returned
    /// On failure, `Err(e)` is returned
    ///
    fn insert_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>>;

    /// Extension function for inserting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueinsertExt::insert_with_seperator`
    fn insert(&mut self, query: &String, value: Value) -> Result<Option<Value>> {
        self.insert_with_seperator(query, '.', value)
    }

}

impl<'doc> TomlValueInsertExt<'doc> for Value {

    fn insert_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>> {
        use resolver::mut_resolver::resolve;

        unimplemented!()
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use error::*;
    use toml::Value;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_insert_with_seperator_into_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let table = t.get("table");
                assert!(table.is_some());

                let table = table.unwrap();
                assert!(is_match!(table, &Value::Table(_)));
                match table {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_insert_with_seperator_into_array() {
        use std::ops::Index;

        let mut toml : Value = toml_from_str(r#"
        array = []
        "#).unwrap();

        let res = toml.insert_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let array = t.get("array");
                assert!(array.is_some());

                let array = array.unwrap();
                assert!(is_match!(array, &Value::Array(_)));
                match array {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

}

<|endoftext|>