<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This module defines the Exonum services interfaces. Like smart contracts in some other
//! blockchain platforms, Exonum services encapsulate business logic of the blockchain application.

use std::fmt;
use std::sync::{Arc, RwLock};
use std::collections::{HashMap, HashSet};
use std::net::SocketAddr;

use serde_json::Value;
use iron::Handler;

use crypto::{Hash, PublicKey, SecretKey};
use storage::{Fork, Snapshot};
use messages::{Message, RawTransaction};
use encoding::Error as MessageError;
use encoding::serialize::json::ExonumJson;
use node::{ApiSender, Node, State, TransactionSend};
use blockchain::{Blockchain, ConsensusConfig, Schema, StoredConfiguration, ValidatorKeys};
use helpers::{Height, Milliseconds, ValidatorId};

/// A trait that describes transaction processing rules (a group of sequential operations
/// with the Exonum storage) for the given `Message`.
pub trait Transaction: Message + ExonumJson + 'static {
    /// Verifies the transaction, which includes the message signature verification and other
    /// specific internal constraints. verify is intended to check the internal consistency of
    /// a transaction; it has no access to the blockchain state.
    /// If a transaction fails verify, it is considered incorrect and cannot be included into
    /// any correct block proposal. Incorrect transactions are never included into the blockchain.
    ///
    /// *This method should not use external data, that is, it must be a pure function.*
    fn verify(&self) -> bool;
    /// Takes the current blockchain state via `fork` and can modify it if certain conditions
    /// are met.
    ///
    /// # Notes
    ///
    /// - When programming `execute`, you should perform state-related checks before any changes
    /// to the state and return early if these checks fail.
    /// - If the execute method of a transaction raises a `panic`, the changes made by the
    /// transactions are discarded, but the transaction itself is still considered committed.
    fn execute(&self, fork: &mut Fork);
}

/// A trait that describes a business-logic of the concrete service.
#[allow(unused_variables, unused_mut)]
pub trait Service: Send + Sync + 'static {
    /// Unique service identification for database schema and service messages.
    fn service_id(&self) -> u16;

    /// Unique human readable service name.
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::blockchain::Service;
    /// use exonum::crypto::Hash;
    /// # use exonum::blockchain::Transaction;
    /// # use exonum::messages::RawTransaction;
    /// # use exonum::encoding::Error as MessageError;
    /// # use exonum::storage::Snapshot;
    ///
    /// struct MyService {}
    ///
    /// impl Service for MyService {
    /// #   fn service_id(&self) -> u16 {
    /// #       8000
    /// #   }
    ///     fn service_name(&self) -> &'static str {
    ///         "my_special_unique_service"
    ///     }
    /// #   fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
    /// #       Vec::new()
    /// #   }
    /// #   fn tx_from_raw(&self, _: RawTransaction) -> Result<Box<Transaction>, MessageError> {
    /// #       unimplemented!()
    /// #   }
    /// }
    /// ```
    fn service_name(&self) -> &'static str;

    /// Returns a list of root hashes of tables that determine the current state
    /// of the service database. These hashes are collected from all services in a common
    ///  `MerklePatriciaTable` that named [`state_hash_aggregator`][1].
    ///
    /// Empty `Vec` can be returned if service don't want to change blockchain state.
    ///
    /// See also [`service_table_unique_key`][2].
    ///
    /// [1]: struct.Schema.html#method.state_hash_aggregator
    /// [2]: struct.Blockchain.html#method.service_table_unique_key
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::blockchain::Service;
    /// use exonum::crypto::Hash;
    /// use exonum::storage::Snapshot;
    /// # use exonum::blockchain::Transaction;
    /// # use exonum::messages::RawTransaction;
    /// # use exonum::encoding::Error as MessageError;
    ///
    /// struct MyService {}
    ///
    /// impl Service for MyService {
    /// #   fn service_id(&self) -> u16 {
    /// #       8000
    /// #   }
    /// #   fn service_name(&self) -> &'static str {
    /// #       "my_special_unique_service"
    /// #   }
    ///     fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
    ///         Vec::new()
    ///     }
    /// #   fn tx_from_raw(&self, _: RawTransaction) -> Result<Box<Transaction>, MessageError> {
    /// #       unimplemented!()
    /// #   }
    /// }
    /// ```
    fn state_hash(&self, snapshot: &Snapshot) -> Vec<Hash>;

    /// Tries to create `Transaction` object from the given raw message.
    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, MessageError>;

    /// By this method you can initialize information schema of service
    /// and generates initial service configuration.
    /// This method is called on genesis block creation event.
    fn initialize(&self, fork: &mut Fork) -> Value {
        Value::Null
    }

    /// Handles commit event. This handler is invoked for each service after commit of the block.
    /// For example service can create some transaction if the specific condition occurred.
    ///
    /// *Try not to perform long operations here*.
    fn handle_commit(&self, context: &ServiceContext) {}

    /// Returns api handler for public users.
    fn public_api_handler(&self, context: &ApiContext) -> Option<Box<Handler>> {
        None
    }

    /// Returns api handler for maintainers.
    fn private_api_handler(&self, context: &ApiContext) -> Option<Box<Handler>> {
        None
    }
}

/// The current node state on which the blockchain is running, or in other words
/// execution context.
#[derive(Debug)]
pub struct ServiceContext {
    validator_id: Option<ValidatorId>,
    service_keypair: (PublicKey, SecretKey),
    api_sender: ApiSender,
    fork: Fork,
    stored_configuration: StoredConfiguration,
    height: Height,
}

impl ServiceContext {
    /// Creates the service context for the given node.
    ///
    /// This method is necessary if you want to implement an alternative exonum node.
    /// For example, you can implement special node without consensus for regression
    /// testing of services business logic.
    pub fn new(
        service_public_key: PublicKey,
        service_secret_key: SecretKey,
        api_sender: ApiSender,
        fork: Fork,
    ) -> ServiceContext {
        let (stored_configuration, height) = {
            let schema = Schema::new(fork.as_ref());
            let stored_configuration = schema.actual_configuration();
            let height = schema.height();
            (stored_configuration, height)
        };
        let validator_id = stored_configuration
            .validator_keys
            .iter()
            .position(|validator| service_public_key == validator.service_key)
            .map(|id| ValidatorId(id as u16));

        ServiceContext {
            validator_id,
            service_keypair: (service_public_key, service_secret_key),
            api_sender,
            fork,
            stored_configuration,
            height,
        }
    }

    /// If the current node is validator returns its identifier.
    /// For other nodes return `None`.
    pub fn validator_id(&self) -> Option<ValidatorId> {
        self.validator_id
    }

    /// Returns the current database snapshot.
    pub fn snapshot(&self) -> &Snapshot {
        self.fork.as_ref()
    }

    /// Returns the current blockchain height. This height is "height of the last committed block".
    pub fn height(&self) -> Height {
        self.height
    }

    /// Returns the current list of validators.
    pub fn validators(&self) -> &[ValidatorKeys] {
        self.stored_configuration.validator_keys.as_slice()
    }

    /// Returns current node's public key.
    pub fn public_key(&self) -> &PublicKey {
        &self.service_keypair.0
    }

    /// Returns current node's secret key.
    pub fn secret_key(&self) -> &SecretKey {
        &self.service_keypair.1
    }

    /// Returns the actual consensus configuration.
    pub fn actual_consensus_config(&self) -> &ConsensusConfig {
        &self.stored_configuration.consensus
    }

    /// Returns service specific global variables as json value.
    pub fn actual_service_config(&self, service: &Service) -> &Value {
        &self.stored_configuration.services[service.service_name()]
    }

    /// Returns reference to the transaction sender.
    pub fn transaction_sender(&self) -> &TransactionSend {
        &self.api_sender
    }

    /// Returns the actual blockchain global configuration.
    pub fn stored_configuration(&self) -> &StoredConfiguration {
        &self.stored_configuration
    }
}

#[derive(Debug, Default)]
pub struct ApiNodeState {
    incoming_connections: HashSet<SocketAddr>,
    outgoing_connections: HashSet<SocketAddr>,
    reconnects_timeout: HashMap<SocketAddr, Milliseconds>,
    //TODO: update on event?
    peers_info: HashMap<SocketAddr, PublicKey>,
}

impl ApiNodeState {
    fn new() -> ApiNodeState {
        Self::default()
    }
}

/// Shared part of the context, used to take some values from the `Node`s `State`
/// should be used to take some metrics.
#[derive(Clone, Debug)]
pub struct SharedNodeState {
    state: Arc<RwLock<ApiNodeState>>,
    /// Timeout to update api state.
    pub state_update_timeout: Milliseconds,
}

impl SharedNodeState {
    /// Creates new `SharedNodeState`
    pub fn new(state_update_timeout: Milliseconds) -> SharedNodeState {
        SharedNodeState {
            state: Arc::new(RwLock::new(ApiNodeState::new())),
            state_update_timeout,
        }
    }
    /// Return list of connected sockets
    pub fn incoming_connections(&self) -> Vec<SocketAddr> {
        self.state
            .read()
            .expect("Expected read lock.")
            .incoming_connections
            .iter()
            .cloned()
            .collect()
    }
    /// Return list of our connection sockets
    pub fn outgoing_connections(&self) -> Vec<SocketAddr> {
        self.state
            .read()
            .expect("Expected read lock.")
            .outgoing_connections
            .iter()
            .cloned()
            .collect()
    }
    /// Return reconnects list
    pub fn reconnects_timeout(&self) -> Vec<(SocketAddr, Milliseconds)> {
        self.state
            .read()
            .expect("Expected read lock.")
            .reconnects_timeout
            .iter()
            .map(|(c, e)| (*c, *e))
            .collect()
    }
    /// Return peers info list
    pub fn peers_info(&self) -> Vec<(SocketAddr, PublicKey)> {
        self.state
            .read()
            .expect("Expected read lock.")
            .peers_info
            .iter()
            .map(|(c, e)| (*c, *e))
            .collect()
    }
    /// Update internal state, from `Node` State`
    pub fn update_node_state(&self, state: &State) {
        for (p, c) in state.peers().iter() {
            self.state
                .write()
                .expect("Expected write lock.")
                .peers_info
                .insert(c.addr(), *p);
        }
    }

    /// Returns value of the `state_update_timeout`.
    pub fn state_update_timeout(&self) -> Milliseconds {
        self.state_update_timeout
    }

    /// add incomming connection into state
    pub fn add_incoming_connection(&self, addr: SocketAddr) {
        self.state
            .write()
            .expect("Expected write lock")
            .incoming_connections
            .insert(addr);
    }
    /// add outgoing connection into state
    pub fn add_outgoing_connection(&self, addr: SocketAddr) {
        self.state
            .write()
            .expect("Expected write lock")
            .outgoing_connections
            .insert(addr);
    }

    /// remove incomming connection from state
    pub fn remove_incoming_connection(&self, addr: &SocketAddr) -> bool {
        self.state
            .write()
            .expect("Expected write lock")
            .incoming_connections
            .remove(addr)
    }

    /// remove outgoing connection from state
    pub fn remove_outgoing_connection(&self, addr: &SocketAddr) -> bool {
        self.state
            .write()
            .expect("Expected write lock")
            .outgoing_connections
            .remove(addr)
    }

    /// Add reconnect timeout
    pub fn add_reconnect_timeout(
        &self,
        addr: SocketAddr,
        timeout: Milliseconds,
    ) -> Option<Milliseconds> {
        self.state
            .write()
            .expect("Expected write lock")
            .reconnects_timeout
            .insert(addr, timeout)
    }

    /// Removes reconnect timeout and returns the previous value.
    pub fn remove_reconnect_timeout(&self, addr: &SocketAddr) -> Option<Milliseconds> {
        self.state
            .write()
            .expect("Expected write lock")
            .reconnects_timeout
            .remove(addr)
    }
}

/// Provides the current node state to api handlers.
pub struct ApiContext {
    blockchain: Blockchain,
    node_channel: ApiSender,
    public_key: PublicKey,
    secret_key: SecretKey,
}

/// Provides the current node state to api handlers.
impl ApiContext {
    /// Constructs context for the given `Node`.
    pub fn new(node: &Node) -> ApiContext {
        let handler = node.handler();
        ApiContext {
            blockchain: handler.blockchain.clone(),
            node_channel: node.channel(),
            public_key: *node.state().service_public_key(),
            secret_key: node.state().service_secret_key().clone(),
        }
    }

    /// Constructs context from raw parts.
    pub fn from_parts(
        blockchain: &Blockchain,
        node_channel: ApiSender,
        public_key: &PublicKey,
        secret_key: &SecretKey,
    ) -> ApiContext {
        ApiContext {
            blockchain: blockchain.clone(),
            node_channel,
            public_key: *public_key,
            secret_key: secret_key.clone(),
        }
    }

    /// Returns reference to the node's blockchain.
    pub fn blockchain(&self) -> &Blockchain {
        &self.blockchain
    }

    /// Returns reference to the transaction sender.
    pub fn node_channel(&self) -> &ApiSender {
        &self.node_channel
    }

    /// Returns the public key of current node.
    pub fn public_key(&self) -> &PublicKey {
        &self.public_key
    }

    /// Returns the secret key of current node.
    pub fn secret_key(&self) -> &SecretKey {
        &self.secret_key
    }
}

impl ::std::fmt::Debug for ApiContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "ApiContext(blockchain: {:?}, public_key: {:?})",
            self.blockchain,
            self.public_key
        )
    }
}

impl<'a, S: Service> From<S> for Box<Service + 'a> {
    fn from(s: S) -> Self {
        Box::new(s) as Box<Service>
    }
}

impl<'a, T: Transaction> From<T> for Box<Transaction + 'a> {
    fn from(tx: T) -> Self {
        Box::new(tx) as Box<Transaction>
    }
}
<commit_msg>Update `Transaction` docs<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This module defines the Exonum services interfaces. Like smart contracts in some other
//! blockchain platforms, Exonum services encapsulate business logic of the blockchain application.

use std::fmt;
use std::sync::{Arc, RwLock};
use std::collections::{HashMap, HashSet};
use std::net::SocketAddr;

use serde_json::Value;
use iron::Handler;

use crypto::{Hash, PublicKey, SecretKey};
use storage::{Fork, Snapshot};
use messages::{Message, RawTransaction};
use encoding::Error as MessageError;
use encoding::serialize::json::ExonumJson;
use node::{ApiSender, Node, State, TransactionSend};
use blockchain::{Blockchain, ConsensusConfig, Schema, StoredConfiguration, ValidatorKeys};
use helpers::{Height, Milliseconds, ValidatorId};

/// Transaction processing functionality for `Message`s allowing to apply authenticated, atomic,
/// constraint-preserving groups of changes to the blockchain storage.
pub trait Transaction: Message + ExonumJson + 'static {
    /// Verifies the internal consistency of the transaction. `verify` should usually include
    /// checking the message signature (via [`verify_signature`]) and, possibly,
    /// other internal constraints. `verify` has no access to the blockchain state;
    /// checks involving the blockchains state must be preformed in [`execute`](#tymethod.execute).
    ///
    /// If a transaction fails `verify`, it is considered incorrect and cannot be included into
    /// any correct block proposal. Incorrect transactions are never included into the blockchain.
    ///
    /// *This method should not use external data, that is, it must be a pure function.*
    ///
    /// [`verify_signature`]: ../messages/trait.Message.html#method.verify_signature
    fn verify(&self) -> bool;
    /// Receives a fork of the current blockchain state and can modify it depending on the contents
    /// of the transaction.
    ///
    /// # Notes
    ///
    /// - When programming `execute`, you should perform state-related checks before any changes
    ///   to the state and return early if these checks fail.
    /// - If the execute method of a transaction raises a panic, the changes made by the
    ///   transaction are discarded, but it is still considered committed.
    fn execute(&self, fork: &mut Fork);
}

/// A trait that describes a business-logic of the concrete service.
#[allow(unused_variables, unused_mut)]
pub trait Service: Send + Sync + 'static {
    /// Unique service identification for database schema and service messages.
    fn service_id(&self) -> u16;

    /// Unique human readable service name.
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::blockchain::Service;
    /// use exonum::crypto::Hash;
    /// # use exonum::blockchain::Transaction;
    /// # use exonum::messages::RawTransaction;
    /// # use exonum::encoding::Error as MessageError;
    /// # use exonum::storage::Snapshot;
    ///
    /// struct MyService {}
    ///
    /// impl Service for MyService {
    /// #   fn service_id(&self) -> u16 {
    /// #       8000
    /// #   }
    ///     fn service_name(&self) -> &'static str {
    ///         "my_special_unique_service"
    ///     }
    /// #   fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
    /// #       Vec::new()
    /// #   }
    /// #   fn tx_from_raw(&self, _: RawTransaction) -> Result<Box<Transaction>, MessageError> {
    /// #       unimplemented!()
    /// #   }
    /// }
    /// ```
    fn service_name(&self) -> &'static str;

    /// Returns a list of root hashes of tables that determine the current state
    /// of the service database. These hashes are collected from all services in a common
    ///  `MerklePatriciaTable` that named [`state_hash_aggregator`][1].
    ///
    /// Empty `Vec` can be returned if service don't want to change blockchain state.
    ///
    /// See also [`service_table_unique_key`][2].
    ///
    /// [1]: struct.Schema.html#method.state_hash_aggregator
    /// [2]: struct.Blockchain.html#method.service_table_unique_key
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::blockchain::Service;
    /// use exonum::crypto::Hash;
    /// use exonum::storage::Snapshot;
    /// # use exonum::blockchain::Transaction;
    /// # use exonum::messages::RawTransaction;
    /// # use exonum::encoding::Error as MessageError;
    ///
    /// struct MyService {}
    ///
    /// impl Service for MyService {
    /// #   fn service_id(&self) -> u16 {
    /// #       8000
    /// #   }
    /// #   fn service_name(&self) -> &'static str {
    /// #       "my_special_unique_service"
    /// #   }
    ///     fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
    ///         Vec::new()
    ///     }
    /// #   fn tx_from_raw(&self, _: RawTransaction) -> Result<Box<Transaction>, MessageError> {
    /// #       unimplemented!()
    /// #   }
    /// }
    /// ```
    fn state_hash(&self, snapshot: &Snapshot) -> Vec<Hash>;

    /// Tries to create `Transaction` object from the given raw message.
    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, MessageError>;

    /// By this method you can initialize information schema of service
    /// and generates initial service configuration.
    /// This method is called on genesis block creation event.
    fn initialize(&self, fork: &mut Fork) -> Value {
        Value::Null
    }

    /// Handles commit event. This handler is invoked for each service after commit of the block.
    /// For example service can create some transaction if the specific condition occurred.
    ///
    /// *Try not to perform long operations here*.
    fn handle_commit(&self, context: &ServiceContext) {}

    /// Returns api handler for public users.
    fn public_api_handler(&self, context: &ApiContext) -> Option<Box<Handler>> {
        None
    }

    /// Returns api handler for maintainers.
    fn private_api_handler(&self, context: &ApiContext) -> Option<Box<Handler>> {
        None
    }
}

/// The current node state on which the blockchain is running, or in other words
/// execution context.
#[derive(Debug)]
pub struct ServiceContext {
    validator_id: Option<ValidatorId>,
    service_keypair: (PublicKey, SecretKey),
    api_sender: ApiSender,
    fork: Fork,
    stored_configuration: StoredConfiguration,
    height: Height,
}

impl ServiceContext {
    /// Creates the service context for the given node.
    ///
    /// This method is necessary if you want to implement an alternative exonum node.
    /// For example, you can implement special node without consensus for regression
    /// testing of services business logic.
    pub fn new(
        service_public_key: PublicKey,
        service_secret_key: SecretKey,
        api_sender: ApiSender,
        fork: Fork,
    ) -> ServiceContext {
        let (stored_configuration, height) = {
            let schema = Schema::new(fork.as_ref());
            let stored_configuration = schema.actual_configuration();
            let height = schema.height();
            (stored_configuration, height)
        };
        let validator_id = stored_configuration
            .validator_keys
            .iter()
            .position(|validator| service_public_key == validator.service_key)
            .map(|id| ValidatorId(id as u16));

        ServiceContext {
            validator_id,
            service_keypair: (service_public_key, service_secret_key),
            api_sender,
            fork,
            stored_configuration,
            height,
        }
    }

    /// If the current node is validator returns its identifier.
    /// For other nodes return `None`.
    pub fn validator_id(&self) -> Option<ValidatorId> {
        self.validator_id
    }

    /// Returns the current database snapshot.
    pub fn snapshot(&self) -> &Snapshot {
        self.fork.as_ref()
    }

    /// Returns the current blockchain height. This height is "height of the last committed block".
    pub fn height(&self) -> Height {
        self.height
    }

    /// Returns the current list of validators.
    pub fn validators(&self) -> &[ValidatorKeys] {
        self.stored_configuration.validator_keys.as_slice()
    }

    /// Returns current node's public key.
    pub fn public_key(&self) -> &PublicKey {
        &self.service_keypair.0
    }

    /// Returns current node's secret key.
    pub fn secret_key(&self) -> &SecretKey {
        &self.service_keypair.1
    }

    /// Returns the actual consensus configuration.
    pub fn actual_consensus_config(&self) -> &ConsensusConfig {
        &self.stored_configuration.consensus
    }

    /// Returns service specific global variables as json value.
    pub fn actual_service_config(&self, service: &Service) -> &Value {
        &self.stored_configuration.services[service.service_name()]
    }

    /// Returns reference to the transaction sender.
    pub fn transaction_sender(&self) -> &TransactionSend {
        &self.api_sender
    }

    /// Returns the actual blockchain global configuration.
    pub fn stored_configuration(&self) -> &StoredConfiguration {
        &self.stored_configuration
    }
}

#[derive(Debug, Default)]
pub struct ApiNodeState {
    incoming_connections: HashSet<SocketAddr>,
    outgoing_connections: HashSet<SocketAddr>,
    reconnects_timeout: HashMap<SocketAddr, Milliseconds>,
    //TODO: update on event?
    peers_info: HashMap<SocketAddr, PublicKey>,
}

impl ApiNodeState {
    fn new() -> ApiNodeState {
        Self::default()
    }
}

/// Shared part of the context, used to take some values from the `Node`s `State`
/// should be used to take some metrics.
#[derive(Clone, Debug)]
pub struct SharedNodeState {
    state: Arc<RwLock<ApiNodeState>>,
    /// Timeout to update api state.
    pub state_update_timeout: Milliseconds,
}

impl SharedNodeState {
    /// Creates new `SharedNodeState`
    pub fn new(state_update_timeout: Milliseconds) -> SharedNodeState {
        SharedNodeState {
            state: Arc::new(RwLock::new(ApiNodeState::new())),
            state_update_timeout,
        }
    }
    /// Return list of connected sockets
    pub fn incoming_connections(&self) -> Vec<SocketAddr> {
        self.state
            .read()
            .expect("Expected read lock.")
            .incoming_connections
            .iter()
            .cloned()
            .collect()
    }
    /// Return list of our connection sockets
    pub fn outgoing_connections(&self) -> Vec<SocketAddr> {
        self.state
            .read()
            .expect("Expected read lock.")
            .outgoing_connections
            .iter()
            .cloned()
            .collect()
    }
    /// Return reconnects list
    pub fn reconnects_timeout(&self) -> Vec<(SocketAddr, Milliseconds)> {
        self.state
            .read()
            .expect("Expected read lock.")
            .reconnects_timeout
            .iter()
            .map(|(c, e)| (*c, *e))
            .collect()
    }
    /// Return peers info list
    pub fn peers_info(&self) -> Vec<(SocketAddr, PublicKey)> {
        self.state
            .read()
            .expect("Expected read lock.")
            .peers_info
            .iter()
            .map(|(c, e)| (*c, *e))
            .collect()
    }
    /// Update internal state, from `Node` State`
    pub fn update_node_state(&self, state: &State) {
        for (p, c) in state.peers().iter() {
            self.state
                .write()
                .expect("Expected write lock.")
                .peers_info
                .insert(c.addr(), *p);
        }
    }

    /// Returns value of the `state_update_timeout`.
    pub fn state_update_timeout(&self) -> Milliseconds {
        self.state_update_timeout
    }

    /// add incomming connection into state
    pub fn add_incoming_connection(&self, addr: SocketAddr) {
        self.state
            .write()
            .expect("Expected write lock")
            .incoming_connections
            .insert(addr);
    }
    /// add outgoing connection into state
    pub fn add_outgoing_connection(&self, addr: SocketAddr) {
        self.state
            .write()
            .expect("Expected write lock")
            .outgoing_connections
            .insert(addr);
    }

    /// remove incomming connection from state
    pub fn remove_incoming_connection(&self, addr: &SocketAddr) -> bool {
        self.state
            .write()
            .expect("Expected write lock")
            .incoming_connections
            .remove(addr)
    }

    /// remove outgoing connection from state
    pub fn remove_outgoing_connection(&self, addr: &SocketAddr) -> bool {
        self.state
            .write()
            .expect("Expected write lock")
            .outgoing_connections
            .remove(addr)
    }

    /// Add reconnect timeout
    pub fn add_reconnect_timeout(
        &self,
        addr: SocketAddr,
        timeout: Milliseconds,
    ) -> Option<Milliseconds> {
        self.state
            .write()
            .expect("Expected write lock")
            .reconnects_timeout
            .insert(addr, timeout)
    }

    /// Removes reconnect timeout and returns the previous value.
    pub fn remove_reconnect_timeout(&self, addr: &SocketAddr) -> Option<Milliseconds> {
        self.state
            .write()
            .expect("Expected write lock")
            .reconnects_timeout
            .remove(addr)
    }
}

/// Provides the current node state to api handlers.
pub struct ApiContext {
    blockchain: Blockchain,
    node_channel: ApiSender,
    public_key: PublicKey,
    secret_key: SecretKey,
}

/// Provides the current node state to api handlers.
impl ApiContext {
    /// Constructs context for the given `Node`.
    pub fn new(node: &Node) -> ApiContext {
        let handler = node.handler();
        ApiContext {
            blockchain: handler.blockchain.clone(),
            node_channel: node.channel(),
            public_key: *node.state().service_public_key(),
            secret_key: node.state().service_secret_key().clone(),
        }
    }

    /// Constructs context from raw parts.
    pub fn from_parts(
        blockchain: &Blockchain,
        node_channel: ApiSender,
        public_key: &PublicKey,
        secret_key: &SecretKey,
    ) -> ApiContext {
        ApiContext {
            blockchain: blockchain.clone(),
            node_channel,
            public_key: *public_key,
            secret_key: secret_key.clone(),
        }
    }

    /// Returns reference to the node's blockchain.
    pub fn blockchain(&self) -> &Blockchain {
        &self.blockchain
    }

    /// Returns reference to the transaction sender.
    pub fn node_channel(&self) -> &ApiSender {
        &self.node_channel
    }

    /// Returns the public key of current node.
    pub fn public_key(&self) -> &PublicKey {
        &self.public_key
    }

    /// Returns the secret key of current node.
    pub fn secret_key(&self) -> &SecretKey {
        &self.secret_key
    }
}

impl ::std::fmt::Debug for ApiContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "ApiContext(blockchain: {:?}, public_key: {:?})",
            self.blockchain,
            self.public_key
        )
    }
}

impl<'a, S: Service> From<S> for Box<Service + 'a> {
    fn from(s: S) -> Self {
        Box::new(s) as Box<Service>
    }
}

impl<'a, T: Transaction> From<T> for Box<Transaction + 'a> {
    fn from(tx: T) -> Self {
        Box::new(tx) as Box<Transaction>
    }
}
<|endoftext|>


<commit_before>#![feature(asm)]
#![feature(box_syntax)]
#![feature(core)]
#![feature(lang_items)]
#![feature(no_std)]
#![no_std]

extern crate core;

use core::mem::size_of;

use common::memory::*;
use common::string::*;

use drivers::keyboard::*;
use drivers::mouse::*;

use graphics::color::*;
use graphics::point::*;
use graphics::size::*;
use graphics::window::*;

use programs::session::*;

#[path="../src/common"]
mod common {
    pub mod debug;
    pub mod memory;
    pub mod pio;
    pub mod string;
    pub mod vector;
}

#[path="../src/drivers"]
mod drivers {
    pub mod disk;
    pub mod keyboard;
    pub mod mouse;
}

#[path="../src/filesystems"]
mod filesystems {
    pub mod unfs;
}

#[path="../src/graphics"]
mod graphics {
    pub mod bmp;
    pub mod color;
    pub mod display;
    pub mod point;
    pub mod size;
    pub mod window;
}

#[path="../src/programs"]
mod programs {
    pub mod session;
}

pub struct Application {
    window: Window,
    output: String,
    command: String,
    scroll: Point
}

impl Application {
    pub fn new() -> Application {
        Application {
            window: Window{
                point: Point::new(220, 100),
                size: Size::new(576, 400),
                title: String::from_str("Terminal"),
                title_color: Color::new(0, 0, 0),
                border_color: Color::new(196, 196, 255),
                content_color: Color::alpha(160, 160, 196, 196),
                shaded: false,
                closed: false,
                dragging: false,
                last_mouse_point: Point::new(0, 0),
                last_mouse_event: MouseEvent {
                    x: 0,
                    y: 0,
                    left_button: false,
                    right_button: false,
                    middle_button: false,
                    valid: false
                }
            },
            output: String::new(),
            command: String::new(),
            scroll: Point::new(0, 0)
        }
    }

    fn is_cmd(&self, name: &String) -> bool{
        return self.command.equals(name) || self.command.starts_with(&(name.clone() + " "));
    }

    fn append(&mut self, line: &String) {
        self.output = self.output.clone() + line + '\n';
    }

    #[allow(unused_variables)]
    unsafe fn on_command(&mut self, session: &mut Session){
        if self.is_cmd(&String::from_str("test")){
            self.append(&String::from_str("Test Command"));
        }else if self.is_cmd(&String::from_str("help")){
            self.append(&String::from_str("Help Command"));
        }
    }
}

impl SessionItem for Application {
    unsafe fn draw(&mut self, session: &mut Session) -> bool{
        let display = &session.display;
        if self.window.draw(display) {
            let scroll = self.scroll;

            let mut col = -scroll.x;
            let cols = self.window.size.width as isize / 8;
            let mut row = -scroll.y;
            let rows = self.window.size.height as isize / 16;

            for c in self.output.iter(){
                if c == '\n' {
                    col = -scroll.x;
                    row += 1;
                }else if c == '\t' {
                    col += 8 - col % 8;
                }else{
                    if col >= 0 && col < cols && row >= 0 && row < rows{
                        let point = Point::new(self.window.point.x + 8 * col, self.window.point.y + 16 * row);
                        display.char(point, c, Color::new(224, 224, 224));
                    }
                    col += 1;
                }
            }

            if col > -scroll.x {
                col = -scroll.x;
                row += 1;
            }

            if col >= 0 && col < cols && row >= 0 && row < rows{
                let point = Point::new(self.window.point.x + 8 * col, self.window.point.y + 16 * row);
                display.char(point, '#', Color::new(255, 255, 255));
                col += 2;
            }

            for c in self.command.iter(){
                if c == '\n' {
                    col = -scroll.x;
                    row += 1;
                }else if c == '\t' {
                    col += 8 - col % 8;
                }else{
                    if col >= 0 && col < cols && row >= 0 && row < rows{
                        let point = Point::new(self.window.point.x + 8 * col, self.window.point.y + 16 * row);
                        display.char(point, c, Color::new(255, 255, 255));
                    }
                    col += 1;
                }
            }

            if row >= rows {
                self.scroll.y += row - rows + 1;
                session.redraw = true;
            }

            if col >= 0 && col < cols && row >= 0 && row < rows{
                let point = Point::new(self.window.point.x + 8 * col, self.window.point.y + 16 * row);
                display.char(point, '_', Color::new(255, 255, 255));
            }

            return true;
        }else{
            return false;
        }
    }

    #[allow(unused_variables)]
    unsafe fn on_key(&mut self, session: &mut Session, key_event: KeyEvent){
        if key_event.pressed {
            match key_event.scancode {
                0x01 => self.window.closed = true,
                _ => ()
            }

            match key_event.character {
                '\x00' => (),
                '\x08' => {
                    if self.command.len() > 0 {
                        self.command = self.command.substr(0, self.command.len() - 1);
                    }
                }
                '\x1B' => self.command = String::new(),
                '\n' => {
                    if self.command.len() > 0 {
                        self.output = self.output.clone() + (self.command.clone() + '\n');
                        self.on_command(session);
                        self.command = String::new();
                    }
                },
                _ => {
                    self.command = self.command.clone() + key_event.character;
                }
            }
        }
    }

    unsafe fn on_mouse(&mut self, session: &mut Session, mouse_event: MouseEvent, allow_catch: bool) -> bool{
        return self.window.on_mouse(session.mouse_point, mouse_event, allow_catch);
    }
}

//Class wrappers

static mut application: *mut Application = 0 as *mut Application;

#[no_mangle]
pub unsafe fn entry(){
    application = alloc(size_of::<Application>()) as *mut Application;
    *application = Application::new();
}

#[no_mangle]
pub unsafe fn draw(session: &mut Session) -> bool{
    if application as usize > 0 {
        return (*application).draw(session);
    }else{
        return false;
    }
}

#[no_mangle]
pub unsafe fn on_key(session: &mut Session, key_event: KeyEvent){
    if application as usize > 0{
        (*application).on_key(session, key_event);
    }
}

#[no_mangle]
pub unsafe fn on_mouse(session: &mut Session, mouse_event: MouseEvent, allow_catch: bool) -> bool{
    if application as usize > 0 {
        return (*application).on_mouse(session, mouse_event, allow_catch);
    }else{
        return false;
    }
}
<commit_msg>Line editing in terminal example<commit_after>#![feature(asm)]
#![feature(box_syntax)]
#![feature(core)]
#![feature(lang_items)]
#![feature(no_std)]
#![no_std]

extern crate core;

use core::mem::size_of;

use common::debug::*;
use common::memory::*;
use common::string::*;

use drivers::keyboard::*;
use drivers::mouse::*;

use graphics::color::*;
use graphics::point::*;
use graphics::size::*;
use graphics::window::*;

use programs::session::*;

#[path="../src/common"]
mod common {
    pub mod debug;
    pub mod memory;
    pub mod pio;
    pub mod string;
    pub mod vector;
}

#[path="../src/drivers"]
mod drivers {
    pub mod disk;
    pub mod keyboard;
    pub mod mouse;
}

#[path="../src/filesystems"]
mod filesystems {
    pub mod unfs;
}

#[path="../src/graphics"]
mod graphics {
    pub mod bmp;
    pub mod color;
    pub mod display;
    pub mod point;
    pub mod size;
    pub mod window;
}

#[path="../src/programs"]
mod programs {
    pub mod session;
}

pub struct Application {
    window: Window,
    output: String,
    command: String,
    offset: usize,
    scroll: Point,
    wrap: bool
}

impl Application {
    pub fn new() -> Application {
        Application {
            window: Window{
                point: Point::new(220, 100),
                size: Size::new(576, 400),
                title: String::from_str("Terminal"),
                title_color: Color::new(0, 0, 0),
                border_color: Color::new(196, 196, 255),
                content_color: Color::alpha(160, 160, 196, 196),
                shaded: false,
                closed: false,
                dragging: false,
                last_mouse_point: Point::new(0, 0),
                last_mouse_event: MouseEvent {
                    x: 0,
                    y: 0,
                    left_button: false,
                    right_button: false,
                    middle_button: false,
                    valid: false
                }
            },
            output: String::new(),
            command: String::new(),
            offset: 0,
            scroll: Point::new(0, 0),
            wrap: true
        }
    }

    fn is_cmd(&self, name: &String) -> bool{
        return self.command.equals(name) || self.command.starts_with(&(name.clone() + " "));
    }

    fn append(&mut self, line: &String) {
        self.output = self.output.clone() + line + '\n';
    }

    #[allow(unused_variables)]
    unsafe fn on_command(&mut self, session: &mut Session){
        if self.is_cmd(&String::from_str("test")){
            self.append(&String::from_str("Test Command"));
        }else if self.is_cmd(&String::from_str("help")){
            self.append(&String::from_str("Help Command"));
        }
    }
}

impl SessionItem for Application {
    unsafe fn draw(&mut self, session: &mut Session) -> bool{
        let display = &session.display;
        if self.window.draw(display) {
            let scroll = self.scroll;

            let mut col = -scroll.x;
            let cols = self.window.size.width as isize / 8;
            let mut row = -scroll.y;
            let rows = self.window.size.height as isize / 16;

            for c in self.output.iter(){
                if self.wrap && col >= cols {
                    col = -scroll.x;
                    row += 1;
                }

                if c == '\n' {
                    col = -scroll.x;
                    row += 1;
                }else if c == '\t' {
                    col += 8 - col % 8;
                }else{
                    if col >= 0 && col < cols && row >= 0 && row < rows{
                        let point = Point::new(self.window.point.x + 8 * col, self.window.point.y + 16 * row);
                        display.char(point, c, Color::new(224, 224, 224));
                    }
                    col += 1;
                }
            }

            if col > -scroll.x {
                col = -scroll.x;
                row += 1;
            }

            if col >= 0 && col < cols && row >= 0 && row < rows{
                let point = Point::new(self.window.point.x + 8 * col, self.window.point.y + 16 * row);
                display.char(point, '#', Color::new(255, 255, 255));
                col += 2;
            }

            let mut i = 0;
            for c in self.command.iter(){
                if self.wrap && col >= cols {
                    col = -scroll.x;
                    row += 1;
                }

                if self.offset == i && col >= 0 && col < cols && row >= 0 && row < rows{
                    let point = Point::new(self.window.point.x + 8 * col, self.window.point.y + 16 * row);
                    display.char(point, '_', Color::new(255, 255, 255));
                }

                if c == '\n' {
                    col = -scroll.x;
                    row += 1;
                }else if c == '\t' {
                    col += 8 - col % 8;
                }else{
                    if col >= 0 && col < cols && row >= 0 && row < rows{
                        let point = Point::new(self.window.point.x + 8 * col, self.window.point.y + 16 * row);
                        display.char(point, c, Color::new(255, 255, 255));
                    }
                    col += 1;
                }

                i += 1;
            }

            if self.wrap && col >= cols {
                col = -scroll.x;
                row += 1;
            }

            if row >= rows {
                self.scroll.y += row - rows + 1;
                session.redraw = true;
            }

            if self.offset == i && col >= 0 && col < cols && row >= 0 && row < rows{
                let point = Point::new(self.window.point.x + 8 * col, self.window.point.y + 16 * row);
                display.char(point, '_', Color::new(255, 255, 255));
            }

            return true;
        }else{
            return false;
        }
    }

    #[allow(unused_variables)]
    unsafe fn on_key(&mut self, session: &mut Session, key_event: KeyEvent){
        if key_event.pressed {
            match key_event.scancode {
                0x01 => self.window.closed = true,
                0x47 => self.offset = 0,
                0x4B => if self.offset > 0 {
                    self.offset -= 1;
                },
                0x4D => if self.offset < self.command.len() {
                    self.offset += 1;
                },
                0x4F => self.offset = self.command.len(),
                _ => ()
            }

            match key_event.character {
                '\x00' => (),
                '\x08' => {
                    if self.offset > 0 {
                        self.command = self.command.substr(0, self.offset - 1) + self.command.substr(self.offset, self.command.len() - self.offset);
                        self.offset -= 1;
                    }
                }
                '\x1B' => self.command = String::new(),
                '\n' => {
                    if self.command.len() > 0 {
                        self.output = self.output.clone() + (self.command.clone() + '\n');
                        self.on_command(session);
                        self.command = String::new();
                        self.offset = 0;
                    }
                },
                _ => {
                    self.command = self.command.substr(0, self.offset) + key_event.character + self.command.substr(self.offset, self.command.len() - self.offset);
                    self.offset += 1;
                }
            }
        }
    }

    unsafe fn on_mouse(&mut self, session: &mut Session, mouse_event: MouseEvent, allow_catch: bool) -> bool{
        return self.window.on_mouse(session.mouse_point, mouse_event, allow_catch);
    }
}

//Class wrappers

static mut application: *mut Application = 0 as *mut Application;

#[no_mangle]
pub unsafe fn entry(){
    application = alloc(size_of::<Application>()) as *mut Application;
    *application = Application::new();
}

#[no_mangle]
pub unsafe fn draw(session: &mut Session) -> bool{
    if application as usize > 0 {
        return (*application).draw(session);
    }else{
        return false;
    }
}

#[no_mangle]
pub unsafe fn on_key(session: &mut Session, key_event: KeyEvent){
    if application as usize > 0{
        (*application).on_key(session, key_event);
    }
}

#[no_mangle]
pub unsafe fn on_mouse(session: &mut Session, mouse_event: MouseEvent, allow_catch: bool) -> bool{
    if application as usize > 0 {
        return (*application).on_mouse(session, mouse_event, allow_catch);
    }else{
        return false;
    }
}
<|endoftext|>


<commit_before>extern crate conv;
extern crate rand;

use self::conv::prelude::*;
use neat::genome::Genome;
use neat::organism::Organism;
use self::rand::distributions::{IndependentSample, Range};

#[derive(Debug, Clone)]
pub struct Specie{
    representative: Genome,
    pub organisms: Vec<Organism>
}

const MUTATION_PROBABILITY: f64 = 0.25f64;
const INTERSPECIE_MATE_PROBABILITY: f64 = 0.001f64;

impl Specie{
    pub fn new(genome: Genome) -> Specie{
        Specie{ organisms: vec![], representative: genome }
    }

    pub fn add(&mut self, organism: Organism){
        self.organisms.push(organism);
    }

    pub fn match_genome(&self, organism: &Organism) -> bool{
        self.representative.is_same_specie(&organism.genome)
    }

    pub fn average_fitness(&self) -> f64{
        let organisms_count = self.organisms.len().value_as::<f64>().unwrap();
        let total_fitness = self.organisms.iter().fold(0f64, |total, organism| total + organism.fitness);
        total_fitness / organisms_count
    }

    pub fn generate_offspring(&mut self, num_of_organisms: usize, population_organisms: &Vec<Organism>){
        let mut rng = rand::thread_rng();
        let offspring: Vec<Organism>;
        {
            let mut selected_organisms = vec![];
            let range = Range::new(0, self.organisms.len());
            for _ in 0..num_of_organisms {
                selected_organisms.push(range.ind_sample(&mut rng));
            }
            offspring = selected_organisms.iter().map(|organism_pos| self.create_child(&self.organisms[*organism_pos], population_organisms)).collect::<Vec<Organism>>();
        }
        self.organisms = offspring;
    }

    pub fn get_representative_genome(&self) -> Genome {
        self.representative.clone()
    }

    fn create_child(&self, organism: &Organism, population_organisms: &Vec<Organism>) -> Organism {
        if rand::random::<f64>() < MUTATION_PROBABILITY || population_organisms.len() < 2 {
            self.create_child_by_mutation(organism)
        } else {
            self.create_child_by_mate(organism, population_organisms)
        }
    }

    fn create_child_by_mutation(&self, organism: &Organism) -> Organism {
        organism.mutate()
    }

    fn create_child_by_mate(&self, organism: &Organism, population_organisms: &Vec<Organism>) -> Organism {
        let mut rng = rand::thread_rng();
        if rand::random::<f64>() > INTERSPECIE_MATE_PROBABILITY {
            let selected_mate = rand::sample(&mut rng, 0..self.organisms.len(), 1)[0];
            organism.mate(&self.organisms[selected_mate])
        }else{
            let selected_mate = rand::sample(&mut rng, 0..population_organisms.len(), 1)[0];
            organism.mate(&population_organisms[selected_mate])
        }
    }
}

#[cfg(test)]
mod tests {
    use neat::*;

    #[test]
    fn specie_should_return_correct_average_fitness(){
        let mut specie = Specie::new(Genome::new());
        let mut organism1 = Organism::new(Genome::new());
        organism1.fitness = 10f64;

        let mut organism2 = Organism::new(Genome::new());
        organism2.fitness = 15f64;

        let mut organism3 = Organism::new(Genome::new());
        organism3.fitness = 20f64;

        specie.add(organism1);
        specie.add(organism2);
        specie.add(organism3);

        assert!(specie.average_fitness() == 15f64);
    }
}

<commit_msg>Propagate specie champion to next generation<commit_after>extern crate conv;
extern crate rand;

use self::conv::prelude::*;
use neat::genome::Genome;
use neat::organism::Organism;
use self::rand::distributions::{IndependentSample, Range};

#[derive(Debug, Clone)]
pub struct Specie{
    representative: Genome,
    pub organisms: Vec<Organism>
}

const MUTATION_PROBABILITY: f64 = 0.25f64;
const INTERSPECIE_MATE_PROBABILITY: f64 = 0.001f64;

impl Specie{
    pub fn new(genome: Genome) -> Specie{
        Specie{ organisms: vec![], representative: genome }
    }

    pub fn add(&mut self, organism: Organism){
        self.organisms.push(organism);
    }

    pub fn match_genome(&self, organism: &Organism) -> bool{
        self.representative.is_same_specie(&organism.genome)
    }

    pub fn average_fitness(&self) -> f64{
        let organisms_count = self.organisms.len().value_as::<f64>().unwrap();
        let total_fitness = self.organisms.iter().fold(0f64, |total, organism| total + organism.fitness);
        total_fitness / organisms_count
    }

    pub fn generate_offspring(&mut self, num_of_organisms: usize, population_organisms: &Vec<Organism>){

        let champion: Option<Organism> = self.organisms.iter().fold(None, |champion, organism| {
            if champion.is_none() || champion.as_ref().unwrap().fitness < organism.fitness {
                Some(organism.clone())
            } else {
                champion
            }
        });

        let mut rng = rand::thread_rng();
        let mut offspring: Vec<Organism>;
        {
            let mut selected_organisms = vec![];
            let range = Range::new(0, self.organisms.len());
            for _ in 0..num_of_organisms - 1 {
                selected_organisms.push(range.ind_sample(&mut rng));
            }
            offspring = selected_organisms.iter().map(|organism_pos| self.create_child(&self.organisms[*organism_pos], population_organisms)).collect::<Vec<Organism>>();
        }

        offspring.push(champion.unwrap());

        self.organisms = offspring;
    }

    pub fn get_representative_genome(&self) -> Genome {
        self.representative.clone()
    }

    fn create_child(&self, organism: &Organism, population_organisms: &Vec<Organism>) -> Organism {
        if rand::random::<f64>() < MUTATION_PROBABILITY || population_organisms.len() < 2 {
            self.create_child_by_mutation(organism)
        } else {
            self.create_child_by_mate(organism, population_organisms)
        }
    }

    fn create_child_by_mutation(&self, organism: &Organism) -> Organism {
        organism.mutate()
    }

    fn create_child_by_mate(&self, organism: &Organism, population_organisms: &Vec<Organism>) -> Organism {
        let mut rng = rand::thread_rng();
        if rand::random::<f64>() > INTERSPECIE_MATE_PROBABILITY {
            let selected_mate = rand::sample(&mut rng, 0..self.organisms.len(), 1)[0];
            organism.mate(&self.organisms[selected_mate])
        }else{
            let selected_mate = rand::sample(&mut rng, 0..population_organisms.len(), 1)[0];
            organism.mate(&population_organisms[selected_mate])
        }
    }
}

#[cfg(test)]
mod tests {
    use neat::*;

    #[test]
    fn specie_should_return_correct_average_fitness(){
        let mut specie = Specie::new(Genome::new());
        let mut organism1 = Organism::new(Genome::new());
        organism1.fitness = 10f64;

        let mut organism2 = Organism::new(Genome::new());
        organism2.fitness = 15f64;

        let mut organism3 = Organism::new(Genome::new());
        organism3.fitness = 20f64;

        specie.add(organism1);
        specie.add(organism2);
        specie.add(organism3);

        assert!(specie.average_fitness() == 15f64);
    }
}

<|endoftext|>


<commit_before>// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::num;
use std::cast;

use color::{Color, FloatColor};
use color::{Channel, FloatChannel};
use color::{RGB, ToRGB, RGBA, ToRGBA};

#[path = "../num_macros.rs"]
mod num_macros;

#[deriving(Clone, Eq)]
pub struct HSV<T> { h: T, s: T, v: T }

impl<T:FloatChannel> HSV<T> {
    pub fn new(h: T, s: T, v: T) -> HSV<T> {
        HSV { h: h, s: s, v: v }
    }
}

impl<T:FloatChannel> Color<T> for HSV<T> {
    #[inline]
    pub fn clamp(&self, lo: T, hi: T) -> HSV<T> {
        HSV::new((*self).h.clamp(&lo, &hi),
                 (*self).s.clamp(&lo, &hi),
                 (*self).v.clamp(&lo, &hi))
    }

    #[inline]
    pub fn inverse(&self) -> HSV<T> {
        HSV::new((*self).h.invert_degrees(),
                 (*self).s.invert_channel(),
                 (*self).v.invert_channel())
    }
}

impl<T:FloatChannel> FloatColor<T> for HSV<T> {
    #[inline]
    pub fn normalize(&self) -> HSV<T> {
        HSV::new((*self).h.normalize_degrees(),
                 (*self).s.clamp(&zero!(T), &one!(T)),
                 (*self).v.clamp(&zero!(T), &one!(T)))
    }
}

pub trait ToHSV {
    pub fn to_hsv<U:FloatChannel>(&self) -> HSV<U>;
}

impl ToHSV for u32 {
    #[inline]
    pub fn to_hsv<U:FloatChannel>(&self) -> HSV<U> {
        fail!("Not yet implemented")
    }
}

impl ToHSV for u64 {
    #[inline]
    pub fn to_hsv<U:FloatChannel>(&self) -> HSV<U> {
        fail!("Not yet implemented")
    }
}

impl<T:Clone + FloatChannel> ToHSV for HSV<T> {
    #[inline]
    pub fn to_hsv<U:FloatChannel>(&self) -> HSV<U> {
        HSV::new((*self).h.to_channel(),
                 (*self).s.to_channel(),
                 (*self).v.to_channel())
    }
}

impl<T:Clone + FloatChannel> ToRGB for HSV<T> {
    pub fn to_rgb<U:Channel>(&self) -> RGB<U> {
        // Algorithm taken from the Wikipedia article on HSL and HSV:
        // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV

        let chr = (*self).v * (*self).s;
        let h = (*self).h / num::cast(60);

        // the 2nd largest component
        let x = chr * (one!(T) - ((h % two!(T)) - one!(T)).abs());

        let mut rgb = cond! (
            (h < num::cast(1)) { RGB::new(chr.clone(), x, zero!(T)) }
            (h < num::cast(2)) { RGB::new(x, chr.clone(), zero!(T)) }
            (h < num::cast(3)) { RGB::new(zero!(T), chr.clone(), x) }
            (h < num::cast(4)) { RGB::new(zero!(T), x, chr.clone()) }
            (h < num::cast(5)) { RGB::new(x, zero!(T), chr.clone()) }
            (h < num::cast(6)) { RGB::new(chr.clone(), zero!(T), x) }
            _                  { RGB::new(zero!(T), zero!(T), zero!(T)) }
        );

        // match the value by adding the same amount to each component
        let mn = (*self).v - chr;

        rgb.r = rgb.r + mn;
        rgb.g = rgb.g + mn;
        rgb.b = rgb.b + mn;

        rgb.to_rgb::<U>()
    }
}

#[deriving(Clone, Eq)]
pub struct HSVA<T> { h: T, s: T, v: T, a: T }

impl<T:FloatChannel> HSVA<T> {
    #[inline]
    pub fn new(h: T, s: T, v: T, a: T) -> HSVA<T> {
        HSVA { h: h, s: s, v: v, a: a }
    }

    #[inline]
    pub fn from_hsv_a(hsv: HSV<T>, a: T) -> HSVA<T> {
        unsafe { cast::transmute((hsv, a)) }
    }

    #[inline]
    pub fn hsv<'a>(&'a self) -> &'a HSV<T> {
        unsafe { cast::transmute(self) }
    }

    #[inline]
    pub fn hsv_mut<'a>(&'a mut self) -> &'a mut HSV<T> {
        unsafe { cast::transmute(self) }
    }
}

impl<T:FloatChannel> Color<T> for HSVA<T> {
    #[inline]
    pub fn clamp(&self, lo: T, hi: T) -> HSVA<T> {
        HSVA::new((*self).h.clamp(&lo, &hi),
                  (*self).s.clamp(&lo, &hi),
                  (*self).v.clamp(&lo, &hi),
                  (*self).a.clamp(&lo, &hi))
    }

    #[inline]
    pub fn inverse(&self) -> HSVA<T> {
        HSVA::new((*self).h.invert_degrees(),
                  (*self).s.invert_channel(),
                  (*self).v.invert_channel(),
                  (*self).a.invert_channel())
    }
}

impl<T:FloatChannel> FloatColor<T> for HSVA<T> {
    #[inline]
    pub fn normalize(&self) -> HSVA<T> {
        HSVA::new((*self).h.normalize_degrees(),
                  (*self).s.clamp(&zero!(T), &one!(T)),
                  (*self).v.clamp(&zero!(T), &one!(T)),
                  (*self).a.clamp(&zero!(T), &one!(T)))
    }
}

pub trait ToHSVA {
    pub fn to_hsva<U:FloatChannel>(&self) -> HSVA<U>;
}

impl ToHSVA for u32 {
    #[inline]
    pub fn to_hsva<U:FloatChannel>(&self) -> HSVA<U> {
        fail!("Not yet implemented")
    }
}

impl ToHSVA for u64 {
    #[inline]
    pub fn to_hsva<U:FloatChannel>(&self) -> HSVA<U> {
        fail!("Not yet implemented")
    }
}

impl<C: ToHSV, T:Clone + FloatChannel> ToHSVA for (C, T) {
    #[inline]
    pub fn to_hsva<U:FloatChannel>(&self) -> HSVA<U> {
        match *self {
            (ref hsv, ref a) =>  {
                HSVA::from_hsv_a(hsv.to_hsv(), a.to_channel())
            }
        }
    }
}

impl<T:Clone + FloatChannel> ToHSVA for HSVA<T> {
    #[inline]
    pub fn to_hsva<U:FloatChannel>(&self) -> HSVA<U> {
        HSVA::new((*self).h.to_channel(),
                  (*self).s.to_channel(),
                  (*self).v.to_channel(),
                  (*self).a.to_channel())
    }
}

impl<T:Clone + FloatChannel> ToRGBA for HSVA<T> {
    #[inline]
    pub fn to_rgba<U:Channel>(&self) -> RGBA<U> {
        RGBA::from_rgb_a(self.hsv().to_rgb(), (*self).a.to_channel())
    }
}
<commit_msg>Add hsv conversion tests<commit_after>// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::num;
use std::cast;

use color::{Color, FloatColor};
use color::{Channel, FloatChannel};
use color::{RGB, ToRGB, RGBA, ToRGBA};

#[path = "../num_macros.rs"]
mod num_macros;

#[deriving(Clone, Eq)]
pub struct HSV<T> { h: T, s: T, v: T }

impl<T:FloatChannel> HSV<T> {
    pub fn new(h: T, s: T, v: T) -> HSV<T> {
        HSV { h: h, s: s, v: v }
    }
}

impl<T:FloatChannel> Color<T> for HSV<T> {
    #[inline]
    pub fn clamp(&self, lo: T, hi: T) -> HSV<T> {
        HSV::new((*self).h.clamp(&lo, &hi),
                 (*self).s.clamp(&lo, &hi),
                 (*self).v.clamp(&lo, &hi))
    }

    #[inline]
    pub fn inverse(&self) -> HSV<T> {
        HSV::new((*self).h.invert_degrees(),
                 (*self).s.invert_channel(),
                 (*self).v.invert_channel())
    }
}

impl<T:FloatChannel> FloatColor<T> for HSV<T> {
    #[inline]
    pub fn normalize(&self) -> HSV<T> {
        HSV::new((*self).h.normalize_degrees(),
                 (*self).s.clamp(&zero!(T), &one!(T)),
                 (*self).v.clamp(&zero!(T), &one!(T)))
    }
}

pub trait ToHSV {
    pub fn to_hsv<U:FloatChannel>(&self) -> HSV<U>;
}

impl ToHSV for u32 {
    #[inline]
    pub fn to_hsv<U:FloatChannel>(&self) -> HSV<U> {
        fail!("Not yet implemented")
    }
}

impl ToHSV for u64 {
    #[inline]
    pub fn to_hsv<U:FloatChannel>(&self) -> HSV<U> {
        fail!("Not yet implemented")
    }
}

impl<T:Clone + FloatChannel> ToHSV for HSV<T> {
    #[inline]
    pub fn to_hsv<U:FloatChannel>(&self) -> HSV<U> {
        HSV::new((*self).h.to_channel(),
                 (*self).s.to_channel(),
                 (*self).v.to_channel())
    }
}

impl<T:Clone + FloatChannel> ToRGB for HSV<T> {
    pub fn to_rgb<U:Channel>(&self) -> RGB<U> {
        // Algorithm taken from the Wikipedia article on HSL and HSV:
        // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV

        let chr = (*self).v * (*self).s;
        let h = (*self).h / num::cast(60);

        // the 2nd largest component
        let x = chr * (one!(T) - ((h % two!(T)) - one!(T)).abs());

        let mut rgb = cond! (
            (h < num::cast(1)) { RGB::new(chr.clone(), x, zero!(T)) }
            (h < num::cast(2)) { RGB::new(x, chr.clone(), zero!(T)) }
            (h < num::cast(3)) { RGB::new(zero!(T), chr.clone(), x) }
            (h < num::cast(4)) { RGB::new(zero!(T), x, chr.clone()) }
            (h < num::cast(5)) { RGB::new(x, zero!(T), chr.clone()) }
            (h < num::cast(6)) { RGB::new(chr.clone(), zero!(T), x) }
            _                  { RGB::new(zero!(T), zero!(T), zero!(T)) }
        );

        // match the value by adding the same amount to each component
        let mn = (*self).v - chr;

        rgb.r = rgb.r + mn;
        rgb.g = rgb.g + mn;
        rgb.b = rgb.b + mn;

        rgb.to_rgb::<U>()
    }
}

#[deriving(Clone, Eq)]
pub struct HSVA<T> { h: T, s: T, v: T, a: T }

impl<T:FloatChannel> HSVA<T> {
    #[inline]
    pub fn new(h: T, s: T, v: T, a: T) -> HSVA<T> {
        HSVA { h: h, s: s, v: v, a: a }
    }

    #[inline]
    pub fn from_hsv_a(hsv: HSV<T>, a: T) -> HSVA<T> {
        unsafe { cast::transmute((hsv, a)) }
    }

    #[inline]
    pub fn hsv<'a>(&'a self) -> &'a HSV<T> {
        unsafe { cast::transmute(self) }
    }

    #[inline]
    pub fn hsv_mut<'a>(&'a mut self) -> &'a mut HSV<T> {
        unsafe { cast::transmute(self) }
    }
}

impl<T:FloatChannel> Color<T> for HSVA<T> {
    #[inline]
    pub fn clamp(&self, lo: T, hi: T) -> HSVA<T> {
        HSVA::new((*self).h.clamp(&lo, &hi),
                  (*self).s.clamp(&lo, &hi),
                  (*self).v.clamp(&lo, &hi),
                  (*self).a.clamp(&lo, &hi))
    }

    #[inline]
    pub fn inverse(&self) -> HSVA<T> {
        HSVA::new((*self).h.invert_degrees(),
                  (*self).s.invert_channel(),
                  (*self).v.invert_channel(),
                  (*self).a.invert_channel())
    }
}

impl<T:FloatChannel> FloatColor<T> for HSVA<T> {
    #[inline]
    pub fn normalize(&self) -> HSVA<T> {
        HSVA::new((*self).h.normalize_degrees(),
                  (*self).s.clamp(&zero!(T), &one!(T)),
                  (*self).v.clamp(&zero!(T), &one!(T)),
                  (*self).a.clamp(&zero!(T), &one!(T)))
    }
}

pub trait ToHSVA {
    pub fn to_hsva<U:FloatChannel>(&self) -> HSVA<U>;
}

impl ToHSVA for u32 {
    #[inline]
    pub fn to_hsva<U:FloatChannel>(&self) -> HSVA<U> {
        fail!("Not yet implemented")
    }
}

impl ToHSVA for u64 {
    #[inline]
    pub fn to_hsva<U:FloatChannel>(&self) -> HSVA<U> {
        fail!("Not yet implemented")
    }
}

impl<C: ToHSV, T:Clone + FloatChannel> ToHSVA for (C, T) {
    #[inline]
    pub fn to_hsva<U:FloatChannel>(&self) -> HSVA<U> {
        match *self {
            (ref hsv, ref a) =>  {
                HSVA::from_hsv_a(hsv.to_hsv(), a.to_channel())
            }
        }
    }
}

impl<T:Clone + FloatChannel> ToHSVA for HSVA<T> {
    #[inline]
    pub fn to_hsva<U:FloatChannel>(&self) -> HSVA<U> {
        HSVA::new((*self).h.to_channel(),
                  (*self).s.to_channel(),
                  (*self).v.to_channel(),
                  (*self).a.to_channel())
    }
}

impl<T:Clone + FloatChannel> ToRGBA for HSVA<T> {
    #[inline]
    pub fn to_rgba<U:Channel>(&self) -> RGBA<U> {
        RGBA::from_rgb_a(self.hsv().to_rgb(), (*self).a.to_channel())
    }
}

#[cfg(test)]
mod tests {
    use color::*;

    #[test]
    fn test_hsv_to_hsv() {
        assert_eq!(HSV::new::<f64>(0.0, 0.0, 1.0).to_hsv::<f32>(), HSV::new::<f32>(0.0, 0.0, 1.0));
        assert_eq!(HSV::new::<f64>(0.0, 1.0, 0.6).to_hsv::<f32>(), HSV::new::<f32>(0.0, 1.0, 0.6));
        assert_eq!(HSV::new::<f64>(120.0, 1.0, 0.6).to_hsv::<f32>(), HSV::new::<f32>(120.0, 1.0, 0.6));
        assert_eq!(HSV::new::<f64>(240.0, 1.0, 0.6).to_hsv::<f32>(), HSV::new::<f32>(240.0, 1.0, 0.6));
    }

    #[test]
    fn test_hsv_to_rgb() {
        assert_eq!(HSV::new::<f32>(0.0, 0.0, 1.0).to_rgb::<u8>(), RGB::new::<u8>(0xFF, 0xFF, 0xFF));
        assert_eq!(HSV::new::<f32>(0.0, 1.0, 0.6).to_rgb::<u8>(), RGB::new::<u8>(0x99, 0x00, 0x00));
        assert_eq!(HSV::new::<f32>(120.0, 1.0, 0.6).to_rgb::<u8>(), RGB::new::<u8>(0x00, 0x99, 0x00));
        assert_eq!(HSV::new::<f32>(240.0, 1.0, 0.6).to_rgb::<u8>(), RGB::new::<u8>(0x00, 0x00, 0x99));
    }

    #[test]
    fn test_tuple_to_hsva() {
        assert_eq!((RGB::new::<u8>(0xFF, 0xFF, 0xFF), 0.5f32).to_hsva::<f32>(), HSVA::new::<f32>(0.0, 0.0, 1.0, 0.5));
        assert_eq!((RGB::new::<u8>(0x99, 0x00, 0x00), 0.5f32).to_hsva::<f32>(), HSVA::new::<f32>(0.0, 1.0, 0.6, 0.5));
        assert_eq!((RGB::new::<u8>(0x00, 0x99, 0x00), 0.5f32).to_hsva::<f32>(), HSVA::new::<f32>(120.0, 1.0, 0.6, 0.5));
        assert_eq!((RGB::new::<u8>(0x00, 0x00, 0x99), 0.5f32).to_hsva::<f32>(), HSVA::new::<f32>(240.0, 1.0, 0.6, 0.5));
    }

    #[test]
    fn test_hsva_to_hsva() {
        assert_eq!(HSVA::new::<f64>(0.0, 0.0, 1.0, 0.5).to_hsva::<f32>(), HSVA::new::<f32>(0.0, 0.0, 1.0, 0.5));
        assert_eq!(HSVA::new::<f64>(0.0, 1.0, 0.6, 0.5).to_hsva::<f32>(), HSVA::new::<f32>(0.0, 1.0, 0.6, 0.5));
        assert_eq!(HSVA::new::<f64>(120.0, 1.0, 0.6, 0.5).to_hsva::<f32>(), HSVA::new::<f32>(120.0, 1.0, 0.6, 0.5));
        assert_eq!(HSVA::new::<f64>(240.0, 1.0, 0.6, 0.5).to_hsva::<f32>(), HSVA::new::<f32>(240.0, 1.0, 0.6, 0.5));
    }

    #[test]
    fn test_hsva_to_rgba() {
        assert_eq!(HSVA::new::<f32>(0.0, 0.0, 1.0, 0.5).to_rgba::<u8>(), RGBA::new::<u8>(0xFF, 0xFF, 0xFF, 0x7F));
        assert_eq!(HSVA::new::<f32>(0.0, 1.0, 0.6, 0.5).to_rgba::<u8>(), RGBA::new::<u8>(0x99, 0x00, 0x00, 0x7F));
        assert_eq!(HSVA::new::<f32>(120.0, 1.0, 0.6, 0.5).to_rgba::<u8>(), RGBA::new::<u8>(0x00, 0x99, 0x00, 0x7F));
        assert_eq!(HSVA::new::<f32>(240.0, 1.0, 0.6, 0.5).to_rgba::<u8>(), RGBA::new::<u8>(0x00, 0x00, 0x99, 0x7F));
    }
}
<|endoftext|>


<commit_before>
use sapper::Result;
use sapper::SapperModule;
use sapper::Request;
use sapper::Response;
use sapper::SapperRouter;

use std::str;

#[derive(Clone)]
pub struct Biz;

impl Biz {
    // those handlers in module Biz
    fn index(req: &mut Request) -> Result<Response> {

        let mut response = Response::new();
        response.write_body("hello, boy!".to_string());

        Ok(response)
    }

    fn test(req: &mut Request) -> Result<Response> {

        let mut response = Response::new();
        response.write_body("hello, test!".to_string());

        Ok(response)
    }

    fn test_post(req: &mut Request) -> Result<Response> {

        println!("in test_post, raw_body: {:?}", req.body());
	req.body().collect(move |chunk| {
        	println!("in body, {:?}", chunk);
	}).boxed();

        let mut response = Response::new();
        response.write_body("hello, I'am post!".to_string());

        Ok(response)
    }
}

// set before, after middleware, and add routers
impl SapperModule for Biz {

    fn before(&self, req: &mut Request) -> Result<()> {
        println!("{}", "in Biz before.");
        Ok(())
    }

    fn after(&self, req: &Request, res: &mut Response) -> Result<()> {
        println!("{}", "in Biz after.");

        Ok(())
    }

    // here add routers ....
    fn router(&self, router: &mut SapperRouter) -> Result<()> {
        // need to use Router struct here

        router.get("/", Biz::index);
        router.get("/123", Biz::index);
        router.get("/test", Biz::test);
        router.post("/test", Biz::test_post);

        Ok(())

    }

}

<commit_msg>remove debug info.<commit_after>
use sapper::Result;
use sapper::SapperModule;
use sapper::Request;
use sapper::Response;
use sapper::SapperRouter;

use std::str;

#[derive(Clone)]
pub struct Biz;

impl Biz {
    // those handlers in module Biz
    fn index(req: &mut Request) -> Result<Response> {

        let mut response = Response::new();
        response.write_body("hello, boy!".to_string());

        Ok(response)
    }

    fn test(req: &mut Request) -> Result<Response> {

        let mut response = Response::new();
        response.write_body("hello, test!".to_string());

        Ok(response)
    }

    fn test_post(req: &mut Request) -> Result<Response> {

        println!("in test_post, raw_body: {:?}", req.body());

        let mut response = Response::new();
        response.write_body("hello, I'am post!".to_string());

        Ok(response)
    }
}

// set before, after middleware, and add routers
impl SapperModule for Biz {

    fn before(&self, req: &mut Request) -> Result<()> {
        println!("{}", "in Biz before.");
        Ok(())
    }

    fn after(&self, req: &Request, res: &mut Response) -> Result<()> {
        println!("{}", "in Biz after.");

        Ok(())
    }

    // here add routers ....
    fn router(&self, router: &mut SapperRouter) -> Result<()> {
        // need to use Router struct here

        router.get("/", Biz::index);
        router.get("/123", Biz::index);
        router.get("/test", Biz::test);
        router.post("/test", Biz::test_post);

        Ok(())

    }

}

<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle initial setup steps for a pool.
// Initial setup steps are steps that do not alter the environment.

use std::collections::{HashMap, HashSet};
use std::fs::OpenOptions;
use std::path::PathBuf;

use serde_json;

use devicemapper::{devnode_to_devno, Device, Sectors};

use stratis::{ErrorEnum, StratisError, StratisResult};

use super::super::super::types::{BlockDevTier, DevUuid, PoolUuid};

use super::super::serde_structs::{BackstoreSave, BlockDevSave, PoolSave};

use super::blockdev::StratBlockDev;
use super::device::{blkdev_size, is_stratis_device};
use super::metadata::BDA;
use super::util::get_stratis_block_devices;

/// Find all Stratis devices.
///
/// Returns a map of pool uuids to a map of devices to devnodes for each pool.
pub fn find_all() -> StratisResult<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {
    let mut pool_map = HashMap::new();

    for devnode in get_stratis_block_devices()? {
        match devnode_to_devno(&devnode)? {
            None => continue,
            Some(devno) => {
                is_stratis_device(&devnode)?.and_then(|pool_uuid| {
                    pool_map
                        .entry(pool_uuid)
                        .or_insert_with(HashMap::new)
                        .insert(Device::from(devno), devnode)
                });
            }
        }
    }
    Ok(pool_map)
}

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
#[allow(implicit_hasher)]
pub fn get_metadata(
    pool_uuid: PoolUuid,
    devnodes: &HashMap<Device, PathBuf>,
) -> StratisResult<Option<PoolSave>> {
    // Get pairs of device nodes and matching BDAs
    // If no BDA, or BDA UUID does not match pool UUID, skip.
    // If there is an error reading the BDA, error. There could have been
    // vital information on that BDA, for example, it may have contained
    // the newest metadata.
    let mut bdas = Vec::new();
    for devnode in devnodes.values() {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?;
        if let Some(bda) = bda {
            if bda.pool_uuid() == pool_uuid {
                bdas.push((devnode, bda));
            }
        }
    }

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = {
        match bdas.iter()
            .filter_map(|&(_, ref bda)| bda.last_update_time())
            .max()
        {
            Some(time) => time,
            None => return Ok(None),
        }
    };

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    for &(devnode, ref bda) in bdas.iter()
        .filter(|&&(_, ref bda)| bda.last_update_time() == Some(most_recent_time))
    {
        let poolsave = OpenOptions::new()
            .read(true)
            .open(devnode)
            .ok()
            .and_then(|mut f| bda.load_state(&mut f).ok())
            .and_then(|opt| opt)
            .and_then(|data| serde_json::from_slice(&data).ok());

        if poolsave.is_some() {
            return Ok(poolsave);
        }
    }

    // If no data has yet returned, we have an error. That is, we should have
    // some metadata, because we have a most recent time, but we failed to
    // get any.
    let err_str = "timestamp indicates data was written, but no data successfully read";
    Err(StratisError::Engine(ErrorEnum::NotFound, err_str.into()))
}

/// Get all the blockdevs corresponding to this pool that can be obtained from
/// the given devices.
/// Returns an error if a BDA can not be read or can not be found on any
/// blockdev in devnodes.
/// Returns an error if the blockdevs obtained do not match the metadata.
/// Returns a tuple, of which the first are the data devs, and the second
/// are the devs that support the cache tier.
/// Precondition: Every device in devnodes has already been determined to
/// belong to the pool with the specified pool uuid.
#[allow(implicit_hasher)]
pub fn get_blockdevs(
    pool_uuid: PoolUuid,
    backstore_save: &BackstoreSave,
    devnodes: &HashMap<Device, PathBuf>,
) -> StratisResult<(Vec<StratBlockDev>, Vec<StratBlockDev>)> {
    let recorded_data_map: HashMap<DevUuid, (usize, &BlockDevSave)> = backstore_save
        .data_devs
        .iter()
        .enumerate()
        .map(|(i, bds)| (bds.uuid, (i, bds)))
        .collect();

    let recorded_cache_map: HashMap<DevUuid, (usize, &BlockDevSave)> =
        match backstore_save.cache_devs {
            Some(ref cache_devs) => cache_devs
                .iter()
                .enumerate()
                .map(|(i, bds)| (bds.uuid, (i, bds)))
                .collect(),
            None => HashMap::new(),
        };

    let mut segment_table: HashMap<DevUuid, Vec<(Sectors, Sectors)>> = HashMap::new();
    for seg in &backstore_save.data_segments {
        segment_table
            .entry(seg.0)
            .or_insert_with(Vec::default)
            .push((seg.1, seg.2))
    }
    if let Some(ref segs) = backstore_save.cache_segments {
        for seg in segs {
            segment_table
                .entry(seg.0)
                .or_insert_with(Vec::default)
                .push((seg.1, seg.2))
        }
    }
    if let Some(ref segs) = backstore_save.meta_segments {
        for seg in segs {
            segment_table
                .entry(seg.0)
                .or_insert_with(Vec::default)
                .push((seg.1, seg.2))
        }
    }

    let (mut datadevs, mut cachedevs) = (vec![], vec![]);
    for (device, devnode) in devnodes {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?.ok_or_else(|| {
            StratisError::Engine(ErrorEnum::NotFound,
                                                 format!("Device {} with devnode {} was previously determined to belong to pool with uuid {} but no BDA was found",
                                                 device,
                                                 devnode.display(),
                                                 pool_uuid))
        })?;

        // Return an error if apparent size of Stratis block device appears to
        // have decreased since metadata was recorded or if size of block
        // device could not be obtained.
        blkdev_size(&OpenOptions::new().read(true).open(devnode)?).and_then(|actual_size| {
            let actual_size_sectors = actual_size.sectors();
            let recorded_size = bda.dev_size();
            if actual_size_sectors < recorded_size {
                let err_msg = format!(
                    "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had recorded size ({}), but actual size is less at ({})",
                    device,
                    devnode.display(),
                    bda.pool_uuid(),
                    bda.dev_uuid(),
                    recorded_size,
                    actual_size
                );
                Err(StratisError::Engine(ErrorEnum::Error, err_msg))
            } else {
                Ok(())
            }
        })?;

        let dev_uuid = bda.dev_uuid();

        // Locate the device in the metadata using its uuid. Return the device
        // metadata and whether it was a cache or a datadev.
        let (tier, (_, bd_save)) = recorded_data_map
            .get(&dev_uuid)
            .map(|bd_save| (BlockDevTier::Data, bd_save))
            .or_else(|| {
                recorded_cache_map
                    .get(&dev_uuid)
                    .map(|bd_save| (BlockDevTier::Cache, bd_save))
            })
            .ok_or_else(|| {
                let err_msg = format!(
                        "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had no record in pool metadata",
                        device,
                        devnode.display(),
                        bda.pool_uuid(),
                        bda.dev_uuid()
                    );
                StratisError::Engine(ErrorEnum::NotFound, err_msg)
            })?;

        // This should always succeed since the actual size is at
        // least the recorded size, so all segments should be
        // available to be allocated. If this fails, the most likely
        // conclusion is metadata corruption.
        let segments = segment_table.get(&dev_uuid);
        match tier {
            BlockDevTier::Data => &mut datadevs,
            BlockDevTier::Cache => &mut cachedevs,
        }.push(StratBlockDev::new(
            *device,
            devnode.to_owned(),
            bda,
            segments.unwrap_or(&vec![]),
            bd_save.user_info.clone(),
            bd_save.hardware_info.clone(),
        )?);
    }

    // Verify that datadevs found match datadevs recorded.
    let current_data_uuids: HashSet<_> = datadevs.iter().map(|b| b.uuid()).collect();
    let recorded_data_uuids: HashSet<_> = recorded_data_map.keys().cloned().collect();
    if current_data_uuids != recorded_data_uuids {
        let err_msg = "Recorded data dev UUIDs != discovered datadev UUIDs";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if datadevs.len() != current_data_uuids.len() {
        let err_msg = "Duplicate data devices found in environment";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    // Verify that cachedevs found match cachedevs recorded.
    let current_cache_uuids: HashSet<_> = cachedevs.iter().map(|b| b.uuid()).collect();
    let recorded_cache_uuids: HashSet<_> = recorded_cache_map.keys().cloned().collect();
    if current_cache_uuids != recorded_cache_uuids {
        let err_msg = "Recorded cache dev UUIDs != discovered cachedev UUIDs";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if cachedevs.len() != current_cache_uuids.len() {
        let err_msg = "Duplicate cache devices found in environment";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    Ok((datadevs, cachedevs))
}
<commit_msg>Abstract the action of getting a blockdev into a separate method<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle initial setup steps for a pool.
// Initial setup steps are steps that do not alter the environment.

use std::collections::{HashMap, HashSet};
use std::fs::OpenOptions;
use std::path::{Path, PathBuf};

use serde_json;

use devicemapper::{devnode_to_devno, Device, Sectors};

use stratis::{ErrorEnum, StratisError, StratisResult};

use super::super::super::types::{BlockDevTier, DevUuid, PoolUuid};

use super::super::serde_structs::{BackstoreSave, BlockDevSave, PoolSave};

use super::blockdev::StratBlockDev;
use super::device::{blkdev_size, is_stratis_device};
use super::metadata::BDA;
use super::util::get_stratis_block_devices;

/// Find all Stratis devices.
///
/// Returns a map of pool uuids to a map of devices to devnodes for each pool.
pub fn find_all() -> StratisResult<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {
    let mut pool_map = HashMap::new();

    for devnode in get_stratis_block_devices()? {
        match devnode_to_devno(&devnode)? {
            None => continue,
            Some(devno) => {
                is_stratis_device(&devnode)?.and_then(|pool_uuid| {
                    pool_map
                        .entry(pool_uuid)
                        .or_insert_with(HashMap::new)
                        .insert(Device::from(devno), devnode)
                });
            }
        }
    }
    Ok(pool_map)
}

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
#[allow(implicit_hasher)]
pub fn get_metadata(
    pool_uuid: PoolUuid,
    devnodes: &HashMap<Device, PathBuf>,
) -> StratisResult<Option<PoolSave>> {
    // Get pairs of device nodes and matching BDAs
    // If no BDA, or BDA UUID does not match pool UUID, skip.
    // If there is an error reading the BDA, error. There could have been
    // vital information on that BDA, for example, it may have contained
    // the newest metadata.
    let mut bdas = Vec::new();
    for devnode in devnodes.values() {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?;
        if let Some(bda) = bda {
            if bda.pool_uuid() == pool_uuid {
                bdas.push((devnode, bda));
            }
        }
    }

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = {
        match bdas.iter()
            .filter_map(|&(_, ref bda)| bda.last_update_time())
            .max()
        {
            Some(time) => time,
            None => return Ok(None),
        }
    };

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    for &(devnode, ref bda) in bdas.iter()
        .filter(|&&(_, ref bda)| bda.last_update_time() == Some(most_recent_time))
    {
        let poolsave = OpenOptions::new()
            .read(true)
            .open(devnode)
            .ok()
            .and_then(|mut f| bda.load_state(&mut f).ok())
            .and_then(|opt| opt)
            .and_then(|data| serde_json::from_slice(&data).ok());

        if poolsave.is_some() {
            return Ok(poolsave);
        }
    }

    // If no data has yet returned, we have an error. That is, we should have
    // some metadata, because we have a most recent time, but we failed to
    // get any.
    let err_str = "timestamp indicates data was written, but no data successfully read";
    Err(StratisError::Engine(ErrorEnum::NotFound, err_str.into()))
}

/// Get all the blockdevs corresponding to this pool that can be obtained from
/// the given devices.
/// Returns an error if a BDA can not be read or can not be found on any
/// blockdev in devnodes.
/// Returns an error if the blockdevs obtained do not match the metadata.
/// Returns a tuple, of which the first are the data devs, and the second
/// are the devs that support the cache tier.
/// Precondition: Every device in devnodes has already been determined to
/// belong to the pool with the specified pool uuid.
#[allow(implicit_hasher)]
pub fn get_blockdevs(
    pool_uuid: PoolUuid,
    backstore_save: &BackstoreSave,
    devnodes: &HashMap<Device, PathBuf>,
) -> StratisResult<(Vec<StratBlockDev>, Vec<StratBlockDev>)> {
    let recorded_data_map: HashMap<DevUuid, (usize, &BlockDevSave)> = backstore_save
        .data_devs
        .iter()
        .enumerate()
        .map(|(i, bds)| (bds.uuid, (i, bds)))
        .collect();

    let recorded_cache_map: HashMap<DevUuid, (usize, &BlockDevSave)> =
        match backstore_save.cache_devs {
            Some(ref cache_devs) => cache_devs
                .iter()
                .enumerate()
                .map(|(i, bds)| (bds.uuid, (i, bds)))
                .collect(),
            None => HashMap::new(),
        };

    let mut segment_table: HashMap<DevUuid, Vec<(Sectors, Sectors)>> = HashMap::new();
    for seg in &backstore_save.data_segments {
        segment_table
            .entry(seg.0)
            .or_insert_with(Vec::default)
            .push((seg.1, seg.2))
    }
    if let Some(ref segs) = backstore_save.cache_segments {
        for seg in segs {
            segment_table
                .entry(seg.0)
                .or_insert_with(Vec::default)
                .push((seg.1, seg.2))
        }
    }
    if let Some(ref segs) = backstore_save.meta_segments {
        for seg in segs {
            segment_table
                .entry(seg.0)
                .or_insert_with(Vec::default)
                .push((seg.1, seg.2))
        }
    }

    // Construct a single StratBlockDev. Return the tier to which the
    // blockdev has been found to belong. Returns an error if the block
    // device has shrunk, no metadata can be found for the block device,
    // or it is impossible to set up the device because the recorded
    // allocation information is impossible.
    fn get_blockdev(
        device: Device,
        devnode: &Path,
        bda: BDA,
        data_map: &HashMap<DevUuid, (usize, &BlockDevSave)>,
        cache_map: &HashMap<DevUuid, (usize, &BlockDevSave)>,
        segment_table: &HashMap<DevUuid, Vec<(Sectors, Sectors)>>,
    ) -> StratisResult<(BlockDevTier, StratBlockDev)> {
        // Return an error if apparent size of Stratis block device appears to
        // have decreased since metadata was recorded or if size of block
        // device could not be obtained.
        blkdev_size(&OpenOptions::new().read(true).open(devnode)?).and_then(|actual_size| {
            let actual_size_sectors = actual_size.sectors();
            let recorded_size = bda.dev_size();
            if actual_size_sectors < recorded_size {
                let err_msg = format!(
                    "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had recorded size ({}), but actual size is less at ({})",
                    device,
                    devnode.display(),
                    bda.pool_uuid(),
                    bda.dev_uuid(),
                    recorded_size,
                    actual_size
                );
                Err(StratisError::Engine(ErrorEnum::Error, err_msg))
            } else {
                Ok(())
            }
        })?;

        let dev_uuid = bda.dev_uuid();

        // Locate the device in the metadata using its uuid. Return the device
        // metadata and whether it was a cache or a datadev.
        let (tier, (_, bd_save)) = data_map
            .get(&dev_uuid)
            .map(|bd_save| (BlockDevTier::Data, bd_save))
            .or_else(|| {
                cache_map
                    .get(&dev_uuid)
                    .map(|bd_save| (BlockDevTier::Cache, bd_save))
            })
            .ok_or_else(|| {
                let err_msg = format!(
                        "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had no record in pool metadata",
                        device,
                        devnode.display(),
                        bda.pool_uuid(),
                        bda.dev_uuid()
                    );
                StratisError::Engine(ErrorEnum::NotFound, err_msg)
            })?;

        // This should always succeed since the actual size is at
        // least the recorded size, so all segments should be
        // available to be allocated. If this fails, the most likely
        // conclusion is metadata corruption.
        let segments = segment_table.get(&dev_uuid);
        Ok((
            tier,
            StratBlockDev::new(
                device,
                devnode.to_owned(),
                bda,
                segments.unwrap_or(&vec![]),
                bd_save.user_info.clone(),
                bd_save.hardware_info.clone(),
            )?,
        ))
    }

    let (mut datadevs, mut cachedevs) = (vec![], vec![]);
    for (device, devnode) in devnodes {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?.ok_or_else(|| {
            StratisError::Engine(ErrorEnum::NotFound,
                                                 format!("Device {} with devnode {} was previously determined to belong to pool with uuid {} but no BDA was found",
                                                 device,
                                                 devnode.display(),
                                                 pool_uuid))
        })?;

        get_blockdev(
            *device,
            devnode,
            bda,
            &recorded_data_map,
            &recorded_cache_map,
            &segment_table,
        ).map(|(tier, blockdev)| {
            match tier {
                BlockDevTier::Data => &mut datadevs,
                BlockDevTier::Cache => &mut cachedevs,
            }.push(blockdev)
        })?;
    }

    // Verify that datadevs found match datadevs recorded.
    let current_data_uuids: HashSet<_> = datadevs.iter().map(|b| b.uuid()).collect();
    let recorded_data_uuids: HashSet<_> = recorded_data_map.keys().cloned().collect();
    if current_data_uuids != recorded_data_uuids {
        let err_msg = "Recorded data dev UUIDs != discovered datadev UUIDs";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if datadevs.len() != current_data_uuids.len() {
        let err_msg = "Duplicate data devices found in environment";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    // Verify that cachedevs found match cachedevs recorded.
    let current_cache_uuids: HashSet<_> = cachedevs.iter().map(|b| b.uuid()).collect();
    let recorded_cache_uuids: HashSet<_> = recorded_cache_map.keys().cloned().collect();
    if current_cache_uuids != recorded_cache_uuids {
        let err_msg = "Recorded cache dev UUIDs != discovered cachedev UUIDs";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if cachedevs.len() != current_cache_uuids.len() {
        let err_msg = "Duplicate cache devices found in environment";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    Ok((datadevs, cachedevs))
}
<|endoftext|>


<commit_before><commit_msg>Remove unused file<commit_after><|endoftext|>