<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.

//! The module containing building blocks for creating blockchains powered by the
//! Exonum framework.
//!
//! Services are the main extension point for the Exonum framework. To create your own service on
//! top of Exonum blockchain you need to define following things:
//!
//! - Define your own information schema.
//! - Create one or more types of messages using a macro `message!` and implement
//! `Transaction` trait for them.
//! - Create data structure that implements `Service` trait.
//! - Optionally you can write api handlers.
//!
//! You may follow the [`minibank`][1] tutorial to get experience of programming your services.
//!
//! [1]: https://github.com/exonum/exonum-doc/blob/master/src/get-started/create-service.md

use vec_map::VecMap;
use byteorder::{ByteOrder, LittleEndian};
use mount::Mount;

use std::sync::Arc;
use std::collections::BTreeMap;
use std::mem;
use std::fmt;
use std::panic;

use crypto::{self, Hash};
use messages::{RawMessage, Precommit, CONSENSUS as CORE_SERVICE};
use node::State;
use storage::{Patch, Database, Snapshot, Fork, Error};
use helpers::{Height, ValidatorId};

pub use self::block::{Block, BlockProof, SCHEMA_MAJOR_VERSION};
pub use self::schema::{Schema, TxLocation, gen_prefix};
pub use self::genesis::GenesisConfig;
pub use self::config::{ValidatorKeys, StoredConfiguration, ConsensusConfig, TimeoutAdjusterConfig};
pub use self::service::{Service, Transaction, ServiceContext, ApiContext, SharedNodeState};

mod block;
mod schema;
mod genesis;
mod service;
#[cfg(test)]
mod tests;

pub mod config;

/// Exonum blockchain instance with the concrete services set and data storage.
/// Only blockchains with the identical set of services and genesis block can be combined
/// into the single network.
pub struct Blockchain {
    db: Box<Database>,
    service_map: Arc<VecMap<Box<Service>>>,
}

impl Blockchain {
    /// Constructs a blockchain for the given `storage` and list of `services`.
    pub fn new(storage: Box<Database>, services: Vec<Box<Service>>) -> Blockchain {
        let mut service_map = VecMap::new();
        for service in services {
            let id = service.service_id() as usize;
            if service_map.contains_key(id) {
                panic!(
                    "Services have already contain service with id={}, please change it.",
                    id
                );
            }
            service_map.insert(id, service);
        }

        Blockchain {
            db: storage,
            service_map: Arc::new(service_map),
        }
    }

    /// Returnts service `VecMap` for all our services.
    pub fn service_map(&self) -> &Arc<VecMap<Box<Service>>> {
        &self.service_map
    }

    /// Creates a readonly snapshot of the current storage state.
    pub fn snapshot(&self) -> Box<Snapshot> {
        self.db.snapshot()
    }

    /// Creates snapshot of the current storage state that can be later committed into storage
    /// via `merge` method.
    pub fn fork(&self) -> Fork {
        self.db.fork()
    }

    /// Tries to create a `Transaction` object from the given raw message.
    /// Raw message can be converted into `Transaction` object only
    /// if following conditions are met.
    ///
    /// - Blockchain has service with the `service_id` of given raw message.
    /// - Service can deserialize given raw message.
    pub fn tx_from_raw(&self, raw: RawMessage) -> Option<Box<Transaction>> {
        let id = raw.service_id() as usize;
        self.service_map.get(id).and_then(|service| {
            service.tx_from_raw(raw).ok()
        })
    }

    /// Commits changes from the patch to the blockchain storage.
    /// See [`Fork`](../storage/struct.Fork.html) for details.
    pub fn merge(&mut self, patch: Patch) -> Result<(), Error> {
        self.db.merge(patch)
    }

    /// Returns the hash of latest committed block.
    ///
    /// # Panics
    ///
    /// - If the genesis block was not committed.
    pub fn last_hash(&self) -> Hash {
        Schema::new(&self.snapshot())
            .block_hashes_by_height()
            .last()
            .unwrap_or_else(Hash::default)
    }

    /// Returns the latest committed block.
    ///
    /// # Panics
    ///
    /// - If the genesis block was not committed.
    pub fn last_block(&self) -> Block {
        Schema::new(&self.snapshot()).last_block().unwrap()
    }

    /// Creates and commits the genesis block for the given genesis configuration.
    pub fn create_genesis_block(&mut self, cfg: GenesisConfig) -> Result<(), Error> {
        let mut config_propose = StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: Height::zero(),
            validator_keys: cfg.validator_keys,
            consensus: cfg.consensus,
            services: BTreeMap::new(),
        };

        let patch = {
            let mut fork = self.fork();
            // Update service tables
            for (_, service) in self.service_map.iter() {
                let cfg = service.initialize(&mut fork);
                let name = service.service_name();
                if config_propose.services.contains_key(name) {
                    panic!(
                        "Services already contain service with '{}' name, please change it",
                        name
                    );
                }
                config_propose.services.insert(name.into(), cfg);
            }
            // Commit actual configuration
            {
                let mut schema = Schema::new(&mut fork);
                if schema.block_hash_by_height(Height::zero()).is_some() {
                    // TODO create genesis block for MemoryDB and compare in hash with zero block
                    return Ok(());
                }
                schema.commit_configuration(config_propose);
            };
            self.merge(fork.into_patch())?;
            self.create_patch(ValidatorId::zero(), Height::zero(), &[], &BTreeMap::new())
                .1
        };
        self.merge(patch)?;
        Ok(())
    }

    /// Helper function to map tuple (`u16`, `u16`) of service table coordinates
    /// to 32 byte value for use as `MerklePatriciaTable` key (it currently
    /// supports only fixed size keys). `hash` function is used to distribute
    /// keys uniformly (compared to padding).
    /// # Arguments
    ///
    /// * `service_id` - `service_id` as returned by instance of type of
    /// `Service` trait
    /// * `table_idx` - index of service table in `Vec`, returned by
    /// `state_hash` method of instance of type of `Service` trait
    // also, it was the first idea around, to use `hash`
    pub fn service_table_unique_key(service_id: u16, table_idx: usize) -> Hash {
        debug_assert!(table_idx <= u16::max_value() as usize);
        let size = mem::size_of::<u16>();
        let mut vec = vec![0; 2 * size];
        LittleEndian::write_u16(&mut vec[0..size], service_id);
        LittleEndian::write_u16(&mut vec[size..2 * size], table_idx as u16);
        crypto::hash(&vec)
    }

    /// Executes the given transactions from pool.
    /// Then it collects the resulting changes from the current storage state and returns them
    /// with the hash of resulting block.
    pub fn create_patch(
        &self,
        proposer_id: ValidatorId,
        height: Height,
        tx_hashes: &[Hash],
        pool: &BTreeMap<Hash, Box<Transaction>>,
    ) -> (Hash, Patch) {
        // Create fork
        let mut fork = self.fork();

        let block_hash = {
            // Get last hash
            let last_hash = self.last_hash();
            // Save & execute transactions
            for (index, hash) in tx_hashes.iter().enumerate() {
                let tx = pool.get(hash).expect(
                    "BUG: Cannot find transaction in pool.",
                );

                fork.checkpoint();

                let r = panic::catch_unwind(panic::AssertUnwindSafe(|| { tx.execute(&mut fork); }));

                match r {
                    Ok(..) => fork.commit(),
                    Err(err) => {
                        if err.is::<Error>() {
                            // Continue panic unwind if the reason is StorageError
                            panic::resume_unwind(err);
                        }
                        fork.rollback();
                        error!("{:?} transaction execution failed: {:?}", tx, err);
                    }
                }

                let mut schema = Schema::new(&mut fork);
                schema.transactions_mut().put(hash, tx.raw().clone());
                schema.block_txs_mut(height).push(*hash);
                let location = TxLocation::new(height, index as u64);
                schema.tx_location_by_tx_hash_mut().put(hash, location);
            }

            // Get tx & state hash
            let (tx_hash, state_hash) = {

                let state_hashes = {
                    let schema = Schema::new(&fork);

                    let vec_core_state = schema.core_state_hash();
                    let mut state_hashes = Vec::new();

                    for (idx, core_table_hash) in vec_core_state.into_iter().enumerate() {
                        let key = Blockchain::service_table_unique_key(CORE_SERVICE, idx);
                        state_hashes.push((key, core_table_hash));
                    }

                    for service in self.service_map.values() {
                        let service_id = service.service_id();
                        let vec_service_state = service.state_hash(&fork);
                        for (idx, service_table_hash) in vec_service_state.into_iter().enumerate() {
                            let key = Blockchain::service_table_unique_key(service_id, idx);
                            state_hashes.push((key, service_table_hash));
                        }
                    }

                    state_hashes
                };

                let mut schema = Schema::new(&mut fork);

                let state_hash = {
                    let mut sum_table = schema.state_hash_aggregator_mut();
                    for (key, hash) in state_hashes {
                        sum_table.put(&key, hash)
                    }
                    sum_table.root_hash()
                };

                let tx_hash = schema.block_txs(height).root_hash();

                (tx_hash, state_hash)
            };

            // Create block
            let block = Block::new(
                SCHEMA_MAJOR_VERSION,
                proposer_id,
                height,
                tx_hashes.len() as u32,
                &last_hash,
                &tx_hash,
                &state_hash,
            );
            trace!("execute block = {:?}", block);
            // Eval block hash
            let block_hash = block.hash();
            // Update height
            let mut schema = Schema::new(&mut fork);
            schema.block_hashes_by_height_mut().push(block_hash);
            // Save block
            schema.blocks_mut().put(&block_hash, block);

            block_hash
        };

        (block_hash, fork.into_patch())
    }

    /// Commits to the storage block that proposes by node `State`.
    /// After that invokes `handle_commit` for each service in order of their identifiers
    /// and returns the list of transactions which were created by the `handle_commit` event.
    #[cfg_attr(feature = "flame_profile", flame)]
    pub fn commit<'a, I>(
        &mut self,
        state: &mut State,
        block_hash: Hash,
        precommits: I,
    ) -> Result<Vec<Box<Transaction>>, Error>
    where
        I: Iterator<Item = &'a Precommit>,
    {
        let (patch, txs) = {
            let mut fork = {
                let patch = state.block(&block_hash).unwrap().patch();
                let mut fork = self.db.fork();
                fork.merge(patch.clone()); // FIXME: avoid cloning here
                fork
            };

            {
                let mut schema = Schema::new(&mut fork);
                for precommit in precommits {
                    schema.precommits_mut(&block_hash).push(precommit.clone());
                }

                // cleanup the consensus messages cache
                schema.consensus_messages_cache_mut().clear();

                state.update_config(schema.actual_configuration());
            }

            let transactions = {
                let mut ctx = ServiceContext::new(state, &fork);
                for service in self.service_map.values() {
                    service.handle_commit(&mut ctx);
                }
                ctx.transactions()
            };

            (fork.into_patch(), transactions)
        };
        self.merge(patch)?;
        Ok(txs)
    }

    /// Returns `Mount` object that aggregates public api handlers.
    pub fn mount_public_api(&self, context: &ApiContext) -> Mount {
        let mut mount = Mount::new();
        for service in self.service_map.values() {
            if let Some(handler) = service.public_api_handler(context) {
                mount.mount(service.service_name(), handler);
            }
        }
        mount
    }

    /// Returns `Mount` object that aggregates private api handlers.
    pub fn mount_private_api(&self, context: &ApiContext) -> Mount {
        let mut mount = Mount::new();
        for service in self.service_map.values() {
            if let Some(handler) = service.private_api_handler(context) {
                mount.mount(service.service_name(), handler);
            }
        }
        mount
    }

    /// Saves raw message to the consensus messages cache
    pub fn save_message(&mut self, raw: &RawMessage) -> Result<(), Error> {
        let mut fork = self.fork();

        {
            let mut schema = Schema::new(&mut fork);
            schema.consensus_messages_cache_mut().push(raw.clone());
        }

        self.merge(fork.into_patch())
    }

    /// Saves a collection of RawMessage to the consensus messages cache with single access to the
    /// Fork instance
    pub fn save_messages<I>(&mut self, iter: I) -> Result<(), Error>
    where
        I: Iterator<Item = RawMessage>,
    {

        // prepare DB
        let mut fork = self.fork();

        {
            let mut schema = Schema::new(&mut fork);
            let mut index = schema.consensus_messages_cache_mut();
            for msg in iter {
                index.push(msg);
            }
        }

        self.merge(fork.into_patch())
    }
}

impl fmt::Debug for Blockchain {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Blockchain(..)")
    }
}

impl Clone for Blockchain {
    fn clone(&self) -> Blockchain {
        Blockchain {
            db: self.db.clone(),
            service_map: self.service_map.clone(),
        }
    }
}
<commit_msg>Tiny code cleanup<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.

//! The module containing building blocks for creating blockchains powered by the
//! Exonum framework.
//!
//! Services are the main extension point for the Exonum framework. To create your own service on
//! top of Exonum blockchain you need to define following things:
//!
//! - Define your own information schema.
//! - Create one or more types of messages using a macro `message!` and implement
//! `Transaction` trait for them.
//! - Create data structure that implements `Service` trait.
//! - Optionally you can write api handlers.
//!
//! You may follow the [`minibank`][1] tutorial to get experience of programming your services.
//!
//! [1]: https://github.com/exonum/exonum-doc/blob/master/src/get-started/create-service.md

use vec_map::VecMap;
use byteorder::{ByteOrder, LittleEndian};
use mount::Mount;

use std::sync::Arc;
use std::collections::BTreeMap;
use std::mem;
use std::fmt;
use std::panic;

use crypto::{self, Hash};
use messages::{RawMessage, Precommit, CONSENSUS as CORE_SERVICE};
use node::State;
use storage::{Patch, Database, Snapshot, Fork, Error};
use helpers::{Height, ValidatorId};

pub use self::block::{Block, BlockProof, SCHEMA_MAJOR_VERSION};
pub use self::schema::{Schema, TxLocation, gen_prefix};
pub use self::genesis::GenesisConfig;
pub use self::config::{ValidatorKeys, StoredConfiguration, ConsensusConfig, TimeoutAdjusterConfig};
pub use self::service::{Service, Transaction, ServiceContext, ApiContext, SharedNodeState};

mod block;
mod schema;
mod genesis;
mod service;
#[cfg(test)]
mod tests;

pub mod config;

/// Exonum blockchain instance with the concrete services set and data storage.
/// Only blockchains with the identical set of services and genesis block can be combined
/// into the single network.
pub struct Blockchain {
    db: Box<Database>,
    service_map: Arc<VecMap<Box<Service>>>,
}

impl Blockchain {
    /// Constructs a blockchain for the given `storage` and list of `services`.
    pub fn new(storage: Box<Database>, services: Vec<Box<Service>>) -> Blockchain {
        let mut service_map = VecMap::new();
        for service in services {
            let id = service.service_id() as usize;
            if service_map.contains_key(id) {
                panic!(
                    "Services have already contain service with id={}, please change it.",
                    id
                );
            }
            service_map.insert(id, service);
        }

        Blockchain {
            db: storage,
            service_map: Arc::new(service_map),
        }
    }

    /// Returnts service `VecMap` for all our services.
    pub fn service_map(&self) -> &Arc<VecMap<Box<Service>>> {
        &self.service_map
    }

    /// Creates a readonly snapshot of the current storage state.
    pub fn snapshot(&self) -> Box<Snapshot> {
        self.db.snapshot()
    }

    /// Creates snapshot of the current storage state that can be later committed into storage
    /// via `merge` method.
    pub fn fork(&self) -> Fork {
        self.db.fork()
    }

    /// Tries to create a `Transaction` object from the given raw message.
    /// Raw message can be converted into `Transaction` object only
    /// if following conditions are met.
    ///
    /// - Blockchain has service with the `service_id` of given raw message.
    /// - Service can deserialize given raw message.
    pub fn tx_from_raw(&self, raw: RawMessage) -> Option<Box<Transaction>> {
        let id = raw.service_id() as usize;
        self.service_map.get(id).and_then(|service| {
            service.tx_from_raw(raw).ok()
        })
    }

    /// Commits changes from the patch to the blockchain storage.
    /// See [`Fork`](../storage/struct.Fork.html) for details.
    pub fn merge(&mut self, patch: Patch) -> Result<(), Error> {
        self.db.merge(patch)
    }

    /// Returns the hash of latest committed block.
    ///
    /// # Panics
    ///
    /// - If the genesis block was not committed.
    pub fn last_hash(&self) -> Hash {
        Schema::new(&self.snapshot())
            .block_hashes_by_height()
            .last()
            .unwrap_or_else(Hash::default)
    }

    /// Returns the latest committed block.
    ///
    /// # Panics
    ///
    /// - If the genesis block was not committed.
    pub fn last_block(&self) -> Block {
        Schema::new(&self.snapshot()).last_block().unwrap()
    }

    /// Creates and commits the genesis block for the given genesis configuration.
    pub fn create_genesis_block(&mut self, cfg: GenesisConfig) -> Result<(), Error> {
        let mut config_propose = StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: Height::zero(),
            validator_keys: cfg.validator_keys,
            consensus: cfg.consensus,
            services: BTreeMap::new(),
        };

        let patch = {
            let mut fork = self.fork();
            // Update service tables
            for (_, service) in self.service_map.iter() {
                let cfg = service.initialize(&mut fork);
                let name = service.service_name();
                if config_propose.services.contains_key(name) {
                    panic!(
                        "Services already contain service with '{}' name, please change it",
                        name
                    );
                }
                config_propose.services.insert(name.into(), cfg);
            }
            // Commit actual configuration
            {
                let mut schema = Schema::new(&mut fork);
                if schema.block_hash_by_height(Height::zero()).is_some() {
                    // TODO create genesis block for MemoryDB and compare in hash with zero block
                    return Ok(());
                }
                schema.commit_configuration(config_propose);
            };
            self.merge(fork.into_patch())?;
            self.create_patch(ValidatorId::zero(), Height::zero(), &[], &BTreeMap::new())
                .1
        };
        self.merge(patch)?;
        Ok(())
    }

    /// Helper function to map tuple (`u16`, `u16`) of service table coordinates
    /// to 32 byte value for use as `MerklePatriciaTable` key (it currently
    /// supports only fixed size keys). `hash` function is used to distribute
    /// keys uniformly (compared to padding).
    /// # Arguments
    ///
    /// * `service_id` - `service_id` as returned by instance of type of
    /// `Service` trait
    /// * `table_idx` - index of service table in `Vec`, returned by
    /// `state_hash` method of instance of type of `Service` trait
    // also, it was the first idea around, to use `hash`
    pub fn service_table_unique_key(service_id: u16, table_idx: usize) -> Hash {
        debug_assert!(table_idx <= u16::max_value() as usize);
        let size = mem::size_of::<u16>();
        let mut vec = vec![0; 2 * size];
        LittleEndian::write_u16(&mut vec[0..size], service_id);
        LittleEndian::write_u16(&mut vec[size..2 * size], table_idx as u16);
        crypto::hash(&vec)
    }

    /// Executes the given transactions from pool.
    /// Then it collects the resulting changes from the current storage state and returns them
    /// with the hash of resulting block.
    pub fn create_patch(
        &self,
        proposer_id: ValidatorId,
        height: Height,
        tx_hashes: &[Hash],
        pool: &BTreeMap<Hash, Box<Transaction>>,
    ) -> (Hash, Patch) {
        // Create fork
        let mut fork = self.fork();

        let block_hash = {
            // Get last hash
            let last_hash = self.last_hash();
            // Save & execute transactions
            for (index, hash) in tx_hashes.iter().enumerate() {
                let tx = pool.get(hash).expect(
                    "BUG: Cannot find transaction in pool.",
                );

                fork.checkpoint();

                let r = panic::catch_unwind(panic::AssertUnwindSafe(|| { tx.execute(&mut fork); }));

                match r {
                    Ok(..) => fork.commit(),
                    Err(err) => {
                        if err.is::<Error>() {
                            // Continue panic unwind if the reason is StorageError
                            panic::resume_unwind(err);
                        }
                        fork.rollback();
                        error!("{:?} transaction execution failed: {:?}", tx, err);
                    }
                }

                let mut schema = Schema::new(&mut fork);
                schema.transactions_mut().put(hash, tx.raw().clone());
                schema.block_txs_mut(height).push(*hash);
                let location = TxLocation::new(height, index as u64);
                schema.tx_location_by_tx_hash_mut().put(hash, location);
            }

            // Get tx & state hash
            let (tx_hash, state_hash) = {

                let state_hashes = {
                    let schema = Schema::new(&fork);

                    let vec_core_state = schema.core_state_hash();
                    let mut state_hashes = Vec::new();

                    for (idx, core_table_hash) in vec_core_state.into_iter().enumerate() {
                        let key = Blockchain::service_table_unique_key(CORE_SERVICE, idx);
                        state_hashes.push((key, core_table_hash));
                    }

                    for service in self.service_map.values() {
                        let service_id = service.service_id();
                        let vec_service_state = service.state_hash(&fork);
                        for (idx, service_table_hash) in vec_service_state.into_iter().enumerate() {
                            let key = Blockchain::service_table_unique_key(service_id, idx);
                            state_hashes.push((key, service_table_hash));
                        }
                    }

                    state_hashes
                };

                let mut schema = Schema::new(&mut fork);

                let state_hash = {
                    let mut sum_table = schema.state_hash_aggregator_mut();
                    for (key, hash) in state_hashes {
                        sum_table.put(&key, hash)
                    }
                    sum_table.root_hash()
                };

                let tx_hash = schema.block_txs(height).root_hash();

                (tx_hash, state_hash)
            };

            // Create block
            let block = Block::new(
                SCHEMA_MAJOR_VERSION,
                proposer_id,
                height,
                tx_hashes.len() as u32,
                &last_hash,
                &tx_hash,
                &state_hash,
            );
            trace!("execute block = {:?}", block);
            // Eval block hash
            let block_hash = block.hash();
            // Update height
            let mut schema = Schema::new(&mut fork);
            schema.block_hashes_by_height_mut().push(block_hash);
            // Save block
            schema.blocks_mut().put(&block_hash, block);

            block_hash
        };

        (block_hash, fork.into_patch())
    }

    /// Commits to the storage block that proposes by node `State`.
    /// After that invokes `handle_commit` for each service in order of their identifiers
    /// and returns the list of transactions which were created by the `handle_commit` event.
    #[cfg_attr(feature = "flame_profile", flame)]
    pub fn commit<'a, I>(
        &mut self,
        state: &mut State,
        block_hash: Hash,
        precommits: I,
    ) -> Result<Vec<Box<Transaction>>, Error>
    where
        I: Iterator<Item = &'a Precommit>,
    {
        let (patch, txs) = {
            let mut fork = {
                let patch = state.block(&block_hash).unwrap().patch();
                let mut fork = self.db.fork();
                fork.merge(patch.clone()); // FIXME: avoid cloning here
                fork
            };

            {
                let mut schema = Schema::new(&mut fork);
                for precommit in precommits {
                    schema.precommits_mut(&block_hash).push(precommit.clone());
                }

                // cleanup the consensus messages cache
                schema.consensus_messages_cache_mut().clear();

                state.update_config(schema.actual_configuration());
            }

            let transactions = {
                let mut ctx = ServiceContext::new(state, &fork);
                for service in self.service_map.values() {
                    service.handle_commit(&mut ctx);
                }
                ctx.transactions()
            };

            (fork.into_patch(), transactions)
        };
        self.merge(patch)?;
        Ok(txs)
    }

    /// Returns `Mount` object that aggregates public api handlers.
    pub fn mount_public_api(&self, context: &ApiContext) -> Mount {
        let mut mount = Mount::new();
        for service in self.service_map.values() {
            if let Some(handler) = service.public_api_handler(context) {
                mount.mount(service.service_name(), handler);
            }
        }
        mount
    }

    /// Returns `Mount` object that aggregates private api handlers.
    pub fn mount_private_api(&self, context: &ApiContext) -> Mount {
        let mut mount = Mount::new();
        for service in self.service_map.values() {
            if let Some(handler) = service.private_api_handler(context) {
                mount.mount(service.service_name(), handler);
            }
        }
        mount
    }

    /// Saves raw message to the consensus messages cache
    pub fn save_message(&mut self, raw: &RawMessage) -> Result<(), Error> {
        let mut fork = self.fork();

        {
            let mut schema = Schema::new(&mut fork);
            schema.consensus_messages_cache_mut().push(raw.clone());
        }

        self.merge(fork.into_patch())
    }

    /// Saves a collection of RawMessage to the consensus messages cache with single access to the
    /// Fork instance
    pub fn save_messages<I>(&mut self, iter: I) -> Result<(), Error>
    where
        I: Iterator<Item = RawMessage>,
    {
        let mut fork = self.fork();

        {
            let mut schema = Schema::new(&mut fork);
            let mut index = schema.consensus_messages_cache_mut();
            for msg in iter {
                index.push(msg);
            }
        }

        self.merge(fork.into_patch())
    }
}

impl fmt::Debug for Blockchain {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Blockchain(..)")
    }
}

impl Clone for Blockchain {
    fn clone(&self) -> Blockchain {
        Blockchain {
            db: self.db.clone(),
            service_map: self.service_map.clone(),
        }
    }
}
<|endoftext|>


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

use libc::{self, c_char, c_int, c_short, c_uint, c_ushort, c_void, size_t, sockaddr, sockaddr_un, socklen_t};
use libc::{ssize_t};
use std::ffi::{CStr, CString};
use std::io::Error;
use std::iter;
use std::mem;
use std::ptr;

pub fn channel() -> Result<(UnixSender, UnixReceiver),c_int> {
    let mut results = [0, 0];
    unsafe {
        if socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, &mut results[0]) >= 0 {
            Ok((UnixSender::from_fd(results[0]), UnixReceiver::from_fd(results[1])))
        } else {
            Err(Error::last_os_error().raw_os_error().unwrap())
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnixReceiver {
    fd: c_int,
}

impl Drop for UnixReceiver {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixReceiver {
    fn from_fd(fd: c_int) -> UnixReceiver {
        UnixReceiver {
            fd: fd,
        }
    }

    pub fn consume(&self) -> UnixReceiver {
        unsafe {
            UnixReceiver::from_fd(libc::dup(self.fd))
        }
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<UnknownUnixChannel>),c_int> {
        unsafe {
            let mut length_data: [usize; 2] = [0, 0];
            let result = libc::recv(self.fd,
                                    &mut length_data[0] as *mut _ as *mut c_void,
                                    mem::size_of::<[usize; 2]>() as size_t,
                                    MSG_WAITALL);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let [data_length, channel_length] = length_data;
            let cmsg_length = mem::size_of::<cmsghdr>() + channel_length * mem::size_of::<c_int>();
            let cmsg_buffer: *mut cmsghdr = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;

            let mut data_buffer: Vec<u8> = iter::repeat(0).take(data_length).collect();
            let mut iovec = iovec {
                iov_base: &mut data_buffer[0] as *mut _ as *mut i8,
                iov_len: data_length as size_t,
            };

            let mut msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = recvmsg(self.fd, &mut msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_fds = cmsg_buffer.offset(1) as *const u8 as *const c_int;
            let channels = (0..channel_length).map(|index| {
                UnknownUnixChannel::from_fd(*cmsg_fds.offset(index as isize))
            }).collect();

            Ok((data_buffer, channels))
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnixSender {
    fd: c_int,
}

impl Drop for UnixSender {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl Clone for UnixSender {
    fn clone(&self) -> UnixSender {
        unsafe {
            UnixSender {
                fd: libc::dup(self.fd)
            }
        }
    }
}

impl UnixSender {
    fn from_fd(fd: c_int) -> UnixSender {
        UnixSender {
            fd: fd,
        }
    }

    pub fn send(&self, data: &[u8], channels: Vec<UnixChannel>) -> Result<(),c_int> {
        unsafe {
            let length_data: [usize; 2] = [data.len(), channels.len()];
            let result = libc::send(self.fd,
                                    &length_data[0] as *const _ as *const c_void,
                                    mem::size_of::<[usize; 2]>() as u64,
                                    0);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_length = mem::size_of::<cmsghdr>() + channels.len() * mem::size_of::<c_int>();
            let cmsg_buffer = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;
            (*cmsg_buffer).cmsg_len = cmsg_length as size_t;
            (*cmsg_buffer).cmsg_level = libc::SOL_SOCKET;
            (*cmsg_buffer).cmsg_type = SCM_RIGHTS;

            let mut fds = Vec::new();
            for channel in channels.into_iter() {
                fds.push(channel.fd());
                mem::forget(channel);
            }
            ptr::copy_nonoverlapping(fds.as_ptr(),
                                     cmsg_buffer.offset(1) as *mut _ as *mut c_int,
                                     fds.len());

            let mut iovec = iovec {
                iov_base: data.as_ptr() as *const i8 as *mut i8,
                iov_len: data.len() as size_t,
            };

            let msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = sendmsg(self.fd, &msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);

            if result > 0 {
                Ok(())
            } else {
                Err(Error::last_os_error().raw_os_error().unwrap())
            }
        }
    }

    pub fn connect(name: String) -> Result<UnixSender,c_int> {
        let name = CString::new(name).unwrap();
        unsafe {
            let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
            let mut sockaddr = sockaddr_un {
                sun_family: libc::AF_UNIX as u16,
                sun_path: [ 0; 108 ],
            };
            libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                          name.as_ptr(),
                          sockaddr.sun_path.len() as size_t);

            let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
            if libc::connect(fd, &sockaddr as *const _ as *const sockaddr, len as c_uint) < 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            Ok(UnixSender {
                fd: fd,
            })
        }
    }
}

#[derive(PartialEq, Debug)]
pub enum UnixChannel {
    Sender(UnixSender),
    Receiver(UnixReceiver),
}

impl UnixChannel {
    fn fd(&self) -> c_int {
        match *self {
            UnixChannel::Sender(ref sender) => sender.fd,
            UnixChannel::Receiver(ref receiver) => receiver.fd,
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnknownUnixChannel {
    fd: c_int,
}

impl Drop for UnknownUnixChannel {
    fn drop(&mut self) {
        unsafe {
            debug_assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnknownUnixChannel {
    fn from_fd(fd: c_int) -> UnknownUnixChannel {
        UnknownUnixChannel {
            fd: fd,
        }
    }

    pub fn to_sender(&mut self) -> UnixSender {
        unsafe {
            UnixSender::from_fd(libc::dup(self.fd))
        }
    }

    pub fn to_receiver(&mut self) -> UnixReceiver {
        unsafe {
            UnixReceiver::from_fd(libc::dup(self.fd))
        }
    }
}

pub struct UnixOneShotServer {
    fd: c_int,
}

impl Drop for UnixOneShotServer {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixOneShotServer {
    pub fn new() -> Result<(UnixOneShotServer, String),c_int> {
        unsafe {
            let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
            let mut path: Vec<u8>;
            loop {
                let path_string = CString::new(b"/tmp/rust-ipc-socket.XXXXXX" as &[u8]).unwrap();
                path = path_string.as_bytes().iter().cloned().collect();
                if mktemp(path.as_mut_ptr() as *mut c_char) == ptr::null_mut() {
                    return Err(Error::last_os_error().raw_os_error().unwrap())
                }

                let mut sockaddr = sockaddr_un {
                    sun_family: libc::AF_UNIX as c_ushort,
                    sun_path: [ 0; 108 ],
                };
                libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                              path.as_ptr() as *const c_char,
                              sockaddr.sun_path.len() as size_t);

                let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
                if libc::bind(fd, &sockaddr as *const _ as *const sockaddr, len as c_uint) == 0 {
                    break
                }

                let errno = Error::last_os_error().raw_os_error().unwrap();
                if errno != libc::EINVAL {
                    return Err(errno)
                }
            }

            if libc::listen(fd, 10) != 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            Ok((UnixOneShotServer {
                fd: fd,
            }, String::from_utf8(CStr::from_ptr(path.as_ptr() as *const c_char).to_bytes().to_owned()).unwrap()))
        }
    }

    pub fn accept(self) -> Result<(UnixReceiver, Vec<u8>, Vec<UnknownUnixChannel>),c_int> {
        unsafe {
            let mut sockaddr = mem::uninitialized();
            let mut sockaddr_len = mem::uninitialized();
            let client_fd = libc::accept(self.fd, &mut sockaddr, &mut sockaddr_len);
            if client_fd < 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let receiver = UnixReceiver {
                fd: client_fd,
            };
            let (data, channels) = try!(receiver.recv());
            Ok((receiver, data, channels))
        }
    }
}

// FFI stuff follows:

const MSG_WAITALL: c_int = 0x100;
const SCM_RIGHTS: c_int = 0x01;

extern {
    fn mktemp(template: *mut c_char) -> *mut c_char;
    fn recvmsg(socket: c_int, message: *mut msghdr, flags: c_int) -> ssize_t;
    fn sendmsg(socket: c_int, message: *const msghdr, flags: c_int) -> ssize_t;
    fn socketpair(domain: c_int, socket_type: c_int, protocol: c_int, sv: *mut c_int) -> c_int;
}

#[repr(C)]
struct msghdr {
    msg_name: *mut c_void,
    msg_namelen: socklen_t,
    msg_iov: *mut iovec,
    msg_iovlen: size_t,
    msg_control: *mut c_void,
    msg_controllen: size_t,
    msg_flags: c_int,
}

#[repr(C)]
struct iovec {
    iov_base: *mut c_char,
    iov_len: size_t,
}

#[cfg(target_os="linux")]
#[repr(C)]
struct cmsghdr {
    cmsg_len: size_t,
    cmsg_level: c_int,
    cmsg_type: c_int,
}

<commit_msg>Remove bogus `target_os="linux"` that was breaking Android<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc::{self, c_char, c_int, c_short, c_uint, c_ushort, c_void, size_t, sockaddr, sockaddr_un, socklen_t};
use libc::{ssize_t};
use std::ffi::{CStr, CString};
use std::io::Error;
use std::iter;
use std::mem;
use std::ptr;

pub fn channel() -> Result<(UnixSender, UnixReceiver),c_int> {
    let mut results = [0, 0];
    unsafe {
        if socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, &mut results[0]) >= 0 {
            Ok((UnixSender::from_fd(results[0]), UnixReceiver::from_fd(results[1])))
        } else {
            Err(Error::last_os_error().raw_os_error().unwrap())
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnixReceiver {
    fd: c_int,
}

impl Drop for UnixReceiver {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixReceiver {
    fn from_fd(fd: c_int) -> UnixReceiver {
        UnixReceiver {
            fd: fd,
        }
    }

    pub fn consume(&self) -> UnixReceiver {
        unsafe {
            UnixReceiver::from_fd(libc::dup(self.fd))
        }
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<UnknownUnixChannel>),c_int> {
        unsafe {
            let mut length_data: [usize; 2] = [0, 0];
            let result = libc::recv(self.fd,
                                    &mut length_data[0] as *mut _ as *mut c_void,
                                    mem::size_of::<[usize; 2]>() as size_t,
                                    MSG_WAITALL);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let [data_length, channel_length] = length_data;
            let cmsg_length = mem::size_of::<cmsghdr>() + channel_length * mem::size_of::<c_int>();
            let cmsg_buffer: *mut cmsghdr = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;

            let mut data_buffer: Vec<u8> = iter::repeat(0).take(data_length).collect();
            let mut iovec = iovec {
                iov_base: &mut data_buffer[0] as *mut _ as *mut i8,
                iov_len: data_length as size_t,
            };

            let mut msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = recvmsg(self.fd, &mut msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_fds = cmsg_buffer.offset(1) as *const u8 as *const c_int;
            let channels = (0..channel_length).map(|index| {
                UnknownUnixChannel::from_fd(*cmsg_fds.offset(index as isize))
            }).collect();

            Ok((data_buffer, channels))
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnixSender {
    fd: c_int,
}

impl Drop for UnixSender {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl Clone for UnixSender {
    fn clone(&self) -> UnixSender {
        unsafe {
            UnixSender {
                fd: libc::dup(self.fd)
            }
        }
    }
}

impl UnixSender {
    fn from_fd(fd: c_int) -> UnixSender {
        UnixSender {
            fd: fd,
        }
    }

    pub fn send(&self, data: &[u8], channels: Vec<UnixChannel>) -> Result<(),c_int> {
        unsafe {
            let length_data: [usize; 2] = [data.len(), channels.len()];
            let result = libc::send(self.fd,
                                    &length_data[0] as *const _ as *const c_void,
                                    mem::size_of::<[usize; 2]>() as u64,
                                    0);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_length = mem::size_of::<cmsghdr>() + channels.len() * mem::size_of::<c_int>();
            let cmsg_buffer = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;
            (*cmsg_buffer).cmsg_len = cmsg_length as size_t;
            (*cmsg_buffer).cmsg_level = libc::SOL_SOCKET;
            (*cmsg_buffer).cmsg_type = SCM_RIGHTS;

            let mut fds = Vec::new();
            for channel in channels.into_iter() {
                fds.push(channel.fd());
                mem::forget(channel);
            }
            ptr::copy_nonoverlapping(fds.as_ptr(),
                                     cmsg_buffer.offset(1) as *mut _ as *mut c_int,
                                     fds.len());

            let mut iovec = iovec {
                iov_base: data.as_ptr() as *const i8 as *mut i8,
                iov_len: data.len() as size_t,
            };

            let msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = sendmsg(self.fd, &msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);

            if result > 0 {
                Ok(())
            } else {
                Err(Error::last_os_error().raw_os_error().unwrap())
            }
        }
    }

    pub fn connect(name: String) -> Result<UnixSender,c_int> {
        let name = CString::new(name).unwrap();
        unsafe {
            let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
            let mut sockaddr = sockaddr_un {
                sun_family: libc::AF_UNIX as u16,
                sun_path: [ 0; 108 ],
            };
            libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                          name.as_ptr(),
                          sockaddr.sun_path.len() as size_t);

            let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
            if libc::connect(fd, &sockaddr as *const _ as *const sockaddr, len as c_uint) < 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            Ok(UnixSender {
                fd: fd,
            })
        }
    }
}

#[derive(PartialEq, Debug)]
pub enum UnixChannel {
    Sender(UnixSender),
    Receiver(UnixReceiver),
}

impl UnixChannel {
    fn fd(&self) -> c_int {
        match *self {
            UnixChannel::Sender(ref sender) => sender.fd,
            UnixChannel::Receiver(ref receiver) => receiver.fd,
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct UnknownUnixChannel {
    fd: c_int,
}

impl Drop for UnknownUnixChannel {
    fn drop(&mut self) {
        unsafe {
            debug_assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnknownUnixChannel {
    fn from_fd(fd: c_int) -> UnknownUnixChannel {
        UnknownUnixChannel {
            fd: fd,
        }
    }

    pub fn to_sender(&mut self) -> UnixSender {
        unsafe {
            UnixSender::from_fd(libc::dup(self.fd))
        }
    }

    pub fn to_receiver(&mut self) -> UnixReceiver {
        unsafe {
            UnixReceiver::from_fd(libc::dup(self.fd))
        }
    }
}

pub struct UnixOneShotServer {
    fd: c_int,
}

impl Drop for UnixOneShotServer {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixOneShotServer {
    pub fn new() -> Result<(UnixOneShotServer, String),c_int> {
        unsafe {
            let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
            let mut path: Vec<u8>;
            loop {
                let path_string = CString::new(b"/tmp/rust-ipc-socket.XXXXXX" as &[u8]).unwrap();
                path = path_string.as_bytes().iter().cloned().collect();
                if mktemp(path.as_mut_ptr() as *mut c_char) == ptr::null_mut() {
                    return Err(Error::last_os_error().raw_os_error().unwrap())
                }

                let mut sockaddr = sockaddr_un {
                    sun_family: libc::AF_UNIX as c_ushort,
                    sun_path: [ 0; 108 ],
                };
                libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                              path.as_ptr() as *const c_char,
                              sockaddr.sun_path.len() as size_t);

                let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
                if libc::bind(fd, &sockaddr as *const _ as *const sockaddr, len as c_uint) == 0 {
                    break
                }

                let errno = Error::last_os_error().raw_os_error().unwrap();
                if errno != libc::EINVAL {
                    return Err(errno)
                }
            }

            if libc::listen(fd, 10) != 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            Ok((UnixOneShotServer {
                fd: fd,
            }, String::from_utf8(CStr::from_ptr(path.as_ptr() as *const c_char).to_bytes().to_owned()).unwrap()))
        }
    }

    pub fn accept(self) -> Result<(UnixReceiver, Vec<u8>, Vec<UnknownUnixChannel>),c_int> {
        unsafe {
            let mut sockaddr = mem::uninitialized();
            let mut sockaddr_len = mem::uninitialized();
            let client_fd = libc::accept(self.fd, &mut sockaddr, &mut sockaddr_len);
            if client_fd < 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let receiver = UnixReceiver {
                fd: client_fd,
            };
            let (data, channels) = try!(receiver.recv());
            Ok((receiver, data, channels))
        }
    }
}

// FFI stuff follows:

const MSG_WAITALL: c_int = 0x100;
const SCM_RIGHTS: c_int = 0x01;

extern {
    fn mktemp(template: *mut c_char) -> *mut c_char;
    fn recvmsg(socket: c_int, message: *mut msghdr, flags: c_int) -> ssize_t;
    fn sendmsg(socket: c_int, message: *const msghdr, flags: c_int) -> ssize_t;
    fn socketpair(domain: c_int, socket_type: c_int, protocol: c_int, sv: *mut c_int) -> c_int;
}

#[repr(C)]
struct msghdr {
    msg_name: *mut c_void,
    msg_namelen: socklen_t,
    msg_iov: *mut iovec,
    msg_iovlen: size_t,
    msg_control: *mut c_void,
    msg_controllen: size_t,
    msg_flags: c_int,
}

#[repr(C)]
struct iovec {
    iov_base: *mut c_char,
    iov_len: size_t,
}

#[repr(C)]
struct cmsghdr {
    cmsg_len: size_t,
    cmsg_level: c_int,
    cmsg_type: c_int,
}

<|endoftext|>


<commit_before>use crate::core::*;
use crate::geometry::Space;
use crate::policies::{FinitePolicy, Policy};
use rand::{
    distributions::Distribution,
    rngs::ThreadRng,
    Rng,
    thread_rng,
};
use std::ops::Add;

pub struct PerturbedPolicy<P, D, R = ThreadRng> {
    pub base_policy: P,
    pub noise_dist: D,

    rng: R,
}

impl<P, D> PerturbedPolicy<P, D> {
    pub fn new(base_policy: P, noise_dist: D) -> Self {
        PerturbedPolicy::with_rng(base_policy, noise_dist, thread_rng())
    }
}

impl<P, D, R> PerturbedPolicy<P, D, R> {
    pub fn with_rng(base_policy: P, noise_dist: D, rng: R) -> Self {
        PerturbedPolicy {
            base_policy,
            noise_dist,
            rng,
        }
    }
}

impl<P, D, R> Algorithm for PerturbedPolicy<P, D, R> {}

impl<S, P, D, R> Policy<S> for PerturbedPolicy<P, D, R>
where
    P: Policy<S>,
    D: Distribution<P::Action>,
    R: Rng,
    P::Action: Add<P::Action, Output = P::Action>,
{
    type Action = P::Action;

    fn sample(&mut self, s: &S) -> P::Action {
        let base_action = self.base_policy.sample(s);
        let perturbation = self.noise_dist.sample(&mut self.rng);

        base_action + perturbation
    }

    fn probability(&mut self, _: &S, _: P::Action) -> f64 {
        unimplemented!()
    }
}

impl<S, P, D, R> FinitePolicy<S> for PerturbedPolicy<P, D, R>
where
    P: FinitePolicy<S>,
    D: Distribution<P::Action>,
    R: Rng,
{
    fn n_actions(&self) -> P::Action {
        self.base_policy.n_actions()
    }

    fn probabilities(&mut self, _: &S) -> Vector<f64> {
        unimplemented!()
    }
}
<commit_msg>feat(policies): add Normal distribution constructor to PerturbedPolicy<commit_after>use crate::core::*;
use crate::geometry::Space;
use crate::policies::{FinitePolicy, Policy};
use rand::{
    distributions::{Distribution, Normal},
    rngs::ThreadRng,
    Rng,
    thread_rng,
};
use std::ops::Add;

pub struct PerturbedPolicy<P, D, R = ThreadRng> {
    pub base_policy: P,
    pub noise_dist: D,

    rng: R,
}

impl<P, D> PerturbedPolicy<P, D> {
    pub fn new(base_policy: P, noise_dist: D) -> Self {
        PerturbedPolicy::with_rng(base_policy, noise_dist, thread_rng())
    }
}

impl<P> PerturbedPolicy<P, Normal> {
    pub fn normal(base_policy: P, std_dev: f64) -> Self {
        PerturbedPolicy::with_rng(base_policy, Normal::new(0.0, std_dev), thread_rng())
    }
}

impl<P, D, R> PerturbedPolicy<P, D, R> {
    pub fn with_rng(base_policy: P, noise_dist: D, rng: R) -> Self {
        PerturbedPolicy {
            base_policy,
            noise_dist,
            rng,
        }
    }
}

impl<P, D, R> Algorithm for PerturbedPolicy<P, D, R> {}

impl<S, P, D, R> Policy<S> for PerturbedPolicy<P, D, R>
where
    P: Policy<S>,
    D: Distribution<P::Action>,
    R: Rng,
    P::Action: Add<P::Action, Output = P::Action>,
{
    type Action = P::Action;

    fn sample(&mut self, s: &S) -> P::Action {
        let base_action = self.base_policy.sample(s);
        let perturbation = self.noise_dist.sample(&mut self.rng);

        base_action + perturbation
    }

    fn probability(&mut self, _: &S, _: P::Action) -> f64 {
        unimplemented!()
    }
}

impl<S, P, D, R> FinitePolicy<S> for PerturbedPolicy<P, D, R>
where
    P: FinitePolicy<S>,
    D: Distribution<P::Action>,
    R: Rng,
{
    fn n_actions(&self) -> P::Action {
        self.base_policy.n_actions()
    }

    fn probabilities(&mut self, _: &S) -> Vector<f64> {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>// revisions: cfail1 cfail2 cfail3
// compile-flags: -Coverflow-checks=on
// build-pass (FIXME(62277): could be check-pass?)

#![allow(warnings)]
#![warn(const_err)]

fn main() {
    255u8 + 1; //~ WARNING this expression will panic at run-time
}
<commit_msg>Fix broken incremental test<commit_after>// revisions: cfail1 cfail2 cfail3
// compile-flags: -Coverflow-checks=on
// build-pass (FIXME(62277): could be check-pass?)

#![warn(const_err)]

fn main() {
    let _ = 255u8 + 1; //~ WARNING attempt to add with overflow
}
<|endoftext|>


<commit_before>fn main() {

    fn even_divisible(n: i64, h: i64) -> bool {
        for elem in 2..h {
            if n % elem != 0 {
                return false;
            }
        }
        true
    }

    for elem in 2521.. {
        if elem % 20 != 0 {
            continue;
        } else if even_divisible(elem, 20) {
            println!("{}", elem);
            break;
        } else {
            if elem >= 10000000000 {
                break;
            }
        }
    }
}
<commit_msg>Refactoring problem_5<commit_after>#![feature(step_by)]

fn main() {

    fn even_divisible(n: usize, h: usize) -> bool {
        for elem in (2..h + 1).rev() {
            if n % elem != 0 {
                return false;
            }
        }
        true
    }

    let max = 20;

    let result: usize = (max..)
        .step_by(max)
        .filter(|&x| even_divisible(x as usize, max))
        .take(1)
        .collect::<Vec<_>>()[0];

    println!("{:?}", result);
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use crate::{
    components::{action_dropdown, command_modal, date, font_awesome, loading, paging},
    extensions::*,
    generated::css_classes::C,
    sleep_with_handle, GMsg,
};
use futures::channel::oneshot;
use iml_api_utils::extract_id;
use iml_wire_types::{
    warp_drive::{ArcCache, Locks},
    Alert, AlertRecordType, AlertSeverity, ApiList, EndpointName as _, Session,
};
use seed::{prelude::*, *};
use std::{collections::HashMap, mem, time::Duration};

enum State {
    Loading,
    Fetching,
    Loaded(ApiList<Alert>, HashMap<u32, Row>),
}

struct Row {
    dropdown: action_dropdown::Model,
}

pub struct Model {
    state: State,
    cancel: Option<oneshot::Sender<()>>,
    pager: paging::Model,
}

impl Default for Model {
    fn default() -> Self {
        Self {
            state: State::Loading,
            cancel: None,
            pager: paging::Model::default(),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Msg {
    ActionDropdown(Box<action_dropdown::IdMsg>),
    ActionsFetched(Box<fetch::ResponseDataResult<ApiList<Alert>>>),
    OpenCommandModal(u32),
    FetchOffset,
    Loop,
    Page(paging::Msg),
    Noop,
}

pub fn update(msg: Msg, cache: &ArcCache, model: &mut Model, orders: &mut impl Orders<Msg, GMsg>) {
    match msg {
        Msg::FetchOffset => {
            if let Ok(cmd) = fetch::Request::api_query(
                Alert::endpoint_name(),
                &[("limit", model.pager.limit()), ("offset", model.pager.offset())],
            )
            .map(|req| req.fetch_json_data(|x| Msg::ActionsFetched(Box::new(x))))
            {
                orders.skip().perform_cmd(cmd);
            } else {
                error!("Could not fetch alerts.");
            };
        }
        Msg::ActionsFetched(r) => {
            let state = mem::replace(&mut model.state, State::Loading);

            model.state = match (*r, state) {
                (Ok(mut resp), State::Loaded(_, mut rows)) => {
                    update_rows(&mut resp, &mut rows);

                    orders
                        .proxy(Msg::Page)
                        .send_msg(paging::Msg::SetTotal(resp.meta.total_count as usize));

                    State::Loaded(resp, rows)
                }
                (Ok(mut resp), State::Fetching) => {
                    let mut rows = HashMap::new();

                    update_rows(&mut resp, &mut rows);

                    State::Loaded(resp, rows)
                }
                (Ok(mut resp), State::Loading) => {
                    let mut rows = HashMap::new();

                    update_rows(&mut resp, &mut rows);

                    orders
                        .proxy(Msg::Page)
                        .send_msg(paging::Msg::SetTotal(resp.meta.total_count as usize));

                    State::Loaded(resp, rows)
                }
                (Err(fail_reason), state) => {
                    error!("An error has occurred {:?}", fail_reason);
                    orders.skip();

                    state
                }
            };

            orders.send_msg(Msg::Loop);
        }
        Msg::ActionDropdown(msg) => {
            let action_dropdown::IdMsg(id, msg) = *msg;

            if let State::Loaded(_, rows) = &mut model.state {
                if let Some(x) = rows.get_mut(&id) {
                    action_dropdown::update(
                        action_dropdown::IdMsg(id, msg),
                        cache,
                        &mut x.dropdown,
                        &mut orders.proxy(|x| Msg::ActionDropdown(Box::new(x))),
                    );
                }
            }
        }
        Msg::OpenCommandModal(id) => {
            orders.send_g_msg(GMsg::OpenCommandModal(command_modal::Input::Ids(vec![id])));
        }
        Msg::Page(msg) => match model.state {
            State::Fetching => {
                orders.skip();
            }
            _ => {
                paging::update(msg.clone(), &mut model.pager, &mut orders.proxy(Msg::Page));

                match msg {
                    paging::Msg::Next | paging::Msg::Prev => {
                        model.state = State::Fetching;
                        orders.send_msg(Msg::FetchOffset);
                    }
                    _ => {}
                }
            }
        },
        Msg::Loop => {
            orders.skip();

            let (cancel, fut) = sleep_with_handle(Duration::from_secs(10), Msg::FetchOffset, Msg::Noop);

            model.cancel = Some(cancel);

            orders.perform_cmd(fut);
        }
        Msg::Noop => {}
    }
}

pub(crate) fn init(orders: &mut impl Orders<Msg, GMsg>) {
    orders
        .proxy(Msg::Page)
        .send_msg(paging::Msg::SetLimit(paging::ROW_OPTS[1]));
    orders.send_msg(Msg::FetchOffset);
}

fn update_rows(alerts: &mut ApiList<Alert>, rows: &mut HashMap<u32, Row>) {
    let (add, remove): (Vec<_>, Vec<_>) = alerts
        .objects
        .iter_mut()
        .partition(|x| x.active.unwrap_or_default() && !is_cmd(x.record_type));

    for x in add {
        rows.entry(x.id).or_insert(Row {
            dropdown: action_dropdown::Model::new(x.affected_composite_ids.take().unwrap_or_default()),
        });
    }

    for x in remove {
        rows.remove(&x.id);
    }
}

pub(crate) fn view(model: &Model, session: Option<&Session>, all_locks: &Locks, sd: &date::Model) -> impl View<Msg> {
    div![match &model.state {
        State::Loading => loading::view(),
        State::Fetching => div![
            class![C.bg_menu_active],
            div![
                class![C.px_6, C.py_4, C.bg_blue_1000],
                div![class![C.font_medium, C.text_lg, C.text_gray_500], "Activities"],
                div![
                    class![C.grid, C.grid_cols_2, C.items_center, C.text_white],
                    div![
                        class![C.col_span_1],
                        paging::page_count_view(&model.pager).map_msg(Msg::Page)
                    ],
                    div![
                        class![C.grid, C.grid_cols_2, C.justify_end],
                        paging::next_prev_view(&model.pager).map_msg(Msg::Page)
                    ],
                ],
            ],
            div![loading::view()]
        ],
        State::Loaded(alerts, rows) => div![
            class![C.bg_menu_active],
            div![
                class![C.px_6, C.py_4, C.bg_blue_1000],
                div![class![C.font_medium, C.text_lg, C.text_gray_500], "Activities"],
                div![
                    class![C.grid, C.grid_cols_2, C.items_center, C.text_white],
                    div![
                        class![C.col_span_1],
                        paging::page_count_view(&model.pager).map_msg(Msg::Page)
                    ],
                    div![
                        class![C.grid, C.grid_cols_2, C.justify_end],
                        paging::next_prev_view(&model.pager).map_msg(Msg::Page)
                    ]
                ],
            ],
            alerts.objects.iter().map(|x| {
                let row = rows.get(&x.id);

                alert_item_view(all_locks, sd, session, x, row)
            })
        ],
    }]
}

fn alert_icon_view(alert: &Alert) -> Node<Msg> {
    let cls = class![C.inline, C.w_4, C.h_4];

    match alert.record_type {
        AlertRecordType::AlertEvent
        | AlertRecordType::LearnEvent
        | AlertRecordType::SyslogEvent
        | AlertRecordType::StorageResourceLearnEvent => font_awesome(cls, "info-circle"),
        x if is_cmd(x) => font_awesome(cls, "terminal"),
        _ => font_awesome(cls, "bell"),
    }
}

fn is_cmd(x: AlertRecordType) -> bool {
    match x {
        AlertRecordType::CommandRunningAlert
        | AlertRecordType::CommandSuccessfulAlert
        | AlertRecordType::CommandErroredAlert
        | AlertRecordType::CommandCancelledAlert => true,
        _ => false,
    }
}

fn alert_item_classes(alert: &Alert) -> (&str, &str, &str) {
    match (alert.record_type, alert.severity) {
        (AlertRecordType::CommandRunningAlert, _) => (C.border_gray_500, C.text_gray_500, C.bg_gray_400),
        (AlertRecordType::CommandSuccessfulAlert, _) => (C.border_green_500, C.text_green_500, C.bg_green_400),
        (AlertRecordType::CommandErroredAlert, _) => (C.border_red_500, C.text_red_500, C.bg_red_400),
        (AlertRecordType::CommandCancelledAlert, _) => (C.border_gray_500, C.text_gray_500, C.bg_gray_400),
        (_, AlertSeverity::DEBUG) => (C.border_gray_500, C.text_gray_500, C.bg_gray_400),
        (_, AlertSeverity::INFO) => (C.border_blue_500, C.text_blue_500, C.bg_blue_400),
        (_, AlertSeverity::WARNING) => (C.border_yellow_500, C.text_yellow_500, C.bg_yellow_400),
        (_, AlertSeverity::ERROR) => (C.border_red_500, C.text_red_500, C.bg_red_400),
        (_, AlertSeverity::CRITICAL) => (C.border_orange_500, C.text_orange_500, C.bg_orange_400),
    }
}

fn alert_item_view(
    all_locks: &Locks,
    sd: &date::Model,
    session: Option<&Session>,
    alert: &Alert,
    row: Option<&Row>,
) -> Node<Msg> {
    let (border_color, icon_color, bg_color) = alert_item_classes(alert);

    let is_active = alert.active.unwrap_or_default();

    div![
        class![
            border_color,
            bg_color => is_active,
            C.bg_menu => !is_active,
            C.border_l_8,
            C.gap_4,
            C.grid_cols_3,
            C.grid_flow_row,
            C.grid,
            C.items_center,
            C.mx_4,
            C.my_6,
            C.p_4,
            C.rounded,
            C.text_white,
        ],
        div![class![C.row_span_1, C.col_span_2], alert.message],
        div![
            class![C.row_span_1, C.col_span_1, C.grid, C.justify_end],
            alert_icon_view(alert).merge_attrs(class![icon_color])
        ],
        div![
            class![C.row_span_1, C.col_span_2, C.whitespace_no_wrap],
            "Started",
            " ",
            date_view(sd, &alert.begin)
        ],
        div![
            class![C.row_span_1, C.col_span_1, C.grid, C.justify_end],
            if let Some(row) = row {
                action_dropdown::unstyled_view(
                    alert.id,
                    &row.dropdown,
                    all_locks,
                    session,
                    class![C.bg_transparent, C.border, C.border_white],
                )
                .map_msg(|x| Msg::ActionDropdown(Box::new(x)))
            } else {
                empty![]
            }
        ],
        if let Some(end) = alert.end.as_ref() {
            vec![
                div![
                    class![C.row_span_1, C.col_span_2, C.whitespace_no_wrap],
                    "Ended",
                    " ",
                    date_view(sd, end)
                ],
                command_details_button(alert),
            ]
        } else {
            vec![]
        }
    ]
}

fn date_view<T>(sd: &date::Model, date: &str) -> Node<T> {
    match chrono::DateTime::parse_from_rfc3339(date) {
        Ok(d) => date::view(sd, &d),
        Err(e) => {
            error!(format!("could not parse the date: '{}': {}", date, e));
            plain![date.to_string()]
        }
    }
}

fn command_details_button(alert: &Alert) -> Node<Msg> {
    if !is_cmd(alert.record_type) {
        return empty![];
    }

    if let Some(id) = extract_id(&alert.alert_item) {
        button![
            class![
                C.border_white,
                C.border,
                C.focus__outline_none,
                C.font_bold,
                C.px_4,
                C.py_2,
                C.rounded,
                C.text_white
            ],
            simple_ev(Ev::Click, Msg::OpenCommandModal(id.parse().unwrap())),
            "Details",
        ]
    } else {
        empty![]
    }
}
<commit_msg>Always show the command_details button for commands (#1856)<commit_after>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use crate::{
    components::{action_dropdown, command_modal, date, font_awesome, loading, paging},
    extensions::*,
    generated::css_classes::C,
    sleep_with_handle, GMsg,
};
use futures::channel::oneshot;
use iml_api_utils::extract_id;
use iml_wire_types::{
    warp_drive::{ArcCache, Locks},
    Alert, AlertRecordType, AlertSeverity, ApiList, EndpointName as _, Session,
};
use seed::{prelude::*, *};
use std::{collections::HashMap, mem, time::Duration};

enum State {
    Loading,
    Fetching,
    Loaded(ApiList<Alert>, HashMap<u32, Row>),
}

struct Row {
    dropdown: action_dropdown::Model,
}

pub struct Model {
    state: State,
    cancel: Option<oneshot::Sender<()>>,
    pager: paging::Model,
}

impl Default for Model {
    fn default() -> Self {
        Self {
            state: State::Loading,
            cancel: None,
            pager: paging::Model::default(),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Msg {
    ActionDropdown(Box<action_dropdown::IdMsg>),
    ActionsFetched(Box<fetch::ResponseDataResult<ApiList<Alert>>>),
    OpenCommandModal(u32),
    FetchOffset,
    Loop,
    Page(paging::Msg),
    Noop,
}

pub fn update(msg: Msg, cache: &ArcCache, model: &mut Model, orders: &mut impl Orders<Msg, GMsg>) {
    match msg {
        Msg::FetchOffset => {
            if let Ok(cmd) = fetch::Request::api_query(
                Alert::endpoint_name(),
                &[("limit", model.pager.limit()), ("offset", model.pager.offset())],
            )
            .map(|req| req.fetch_json_data(|x| Msg::ActionsFetched(Box::new(x))))
            {
                orders.skip().perform_cmd(cmd);
            } else {
                error!("Could not fetch alerts.");
            };
        }
        Msg::ActionsFetched(r) => {
            let state = mem::replace(&mut model.state, State::Loading);

            model.state = match (*r, state) {
                (Ok(mut resp), State::Loaded(_, mut rows)) => {
                    update_rows(&mut resp, &mut rows);

                    orders
                        .proxy(Msg::Page)
                        .send_msg(paging::Msg::SetTotal(resp.meta.total_count as usize));

                    State::Loaded(resp, rows)
                }
                (Ok(mut resp), State::Fetching) => {
                    let mut rows = HashMap::new();

                    update_rows(&mut resp, &mut rows);

                    State::Loaded(resp, rows)
                }
                (Ok(mut resp), State::Loading) => {
                    let mut rows = HashMap::new();

                    update_rows(&mut resp, &mut rows);

                    orders
                        .proxy(Msg::Page)
                        .send_msg(paging::Msg::SetTotal(resp.meta.total_count as usize));

                    State::Loaded(resp, rows)
                }
                (Err(fail_reason), state) => {
                    error!("An error has occurred {:?}", fail_reason);
                    orders.skip();

                    state
                }
            };

            orders.send_msg(Msg::Loop);
        }
        Msg::ActionDropdown(msg) => {
            let action_dropdown::IdMsg(id, msg) = *msg;

            if let State::Loaded(_, rows) = &mut model.state {
                if let Some(x) = rows.get_mut(&id) {
                    action_dropdown::update(
                        action_dropdown::IdMsg(id, msg),
                        cache,
                        &mut x.dropdown,
                        &mut orders.proxy(|x| Msg::ActionDropdown(Box::new(x))),
                    );
                }
            }
        }
        Msg::OpenCommandModal(id) => {
            orders.send_g_msg(GMsg::OpenCommandModal(command_modal::Input::Ids(vec![id])));
        }
        Msg::Page(msg) => match model.state {
            State::Fetching => {
                orders.skip();
            }
            _ => {
                paging::update(msg.clone(), &mut model.pager, &mut orders.proxy(Msg::Page));

                match msg {
                    paging::Msg::Next | paging::Msg::Prev => {
                        model.state = State::Fetching;
                        orders.send_msg(Msg::FetchOffset);
                    }
                    _ => {}
                }
            }
        },
        Msg::Loop => {
            orders.skip();

            let (cancel, fut) = sleep_with_handle(Duration::from_secs(10), Msg::FetchOffset, Msg::Noop);

            model.cancel = Some(cancel);

            orders.perform_cmd(fut);
        }
        Msg::Noop => {}
    }
}

pub(crate) fn init(orders: &mut impl Orders<Msg, GMsg>) {
    orders
        .proxy(Msg::Page)
        .send_msg(paging::Msg::SetLimit(paging::ROW_OPTS[1]));
    orders.send_msg(Msg::FetchOffset);
}

fn update_rows(alerts: &mut ApiList<Alert>, rows: &mut HashMap<u32, Row>) {
    let (add, remove): (Vec<_>, Vec<_>) = alerts
        .objects
        .iter_mut()
        .partition(|x| x.active.unwrap_or_default() && !is_cmd(x.record_type));

    for x in add {
        rows.entry(x.id).or_insert(Row {
            dropdown: action_dropdown::Model::new(x.affected_composite_ids.take().unwrap_or_default()),
        });
    }

    for x in remove {
        rows.remove(&x.id);
    }
}

pub(crate) fn view(model: &Model, session: Option<&Session>, all_locks: &Locks, sd: &date::Model) -> impl View<Msg> {
    div![match &model.state {
        State::Loading => loading::view(),
        State::Fetching => div![
            class![C.bg_menu_active],
            div![
                class![C.px_6, C.py_4, C.bg_blue_1000],
                div![class![C.font_medium, C.text_lg, C.text_gray_500], "Activities"],
                div![
                    class![C.grid, C.grid_cols_2, C.items_center, C.text_white],
                    div![
                        class![C.col_span_1],
                        paging::page_count_view(&model.pager).map_msg(Msg::Page)
                    ],
                    div![
                        class![C.grid, C.grid_cols_2, C.justify_end],
                        paging::next_prev_view(&model.pager).map_msg(Msg::Page)
                    ],
                ],
            ],
            div![loading::view()]
        ],
        State::Loaded(alerts, rows) => div![
            class![C.bg_menu_active],
            div![
                class![C.px_6, C.py_4, C.bg_blue_1000],
                div![class![C.font_medium, C.text_lg, C.text_gray_500], "Activities"],
                div![
                    class![C.grid, C.grid_cols_2, C.items_center, C.text_white],
                    div![
                        class![C.col_span_1],
                        paging::page_count_view(&model.pager).map_msg(Msg::Page)
                    ],
                    div![
                        class![C.grid, C.grid_cols_2, C.justify_end],
                        paging::next_prev_view(&model.pager).map_msg(Msg::Page)
                    ]
                ],
            ],
            alerts.objects.iter().map(|x| {
                let row = rows.get(&x.id);

                alert_item_view(all_locks, sd, session, x, row)
            })
        ],
    }]
}

fn alert_icon_view(alert: &Alert) -> Node<Msg> {
    let cls = class![C.inline, C.w_4, C.h_4];

    match alert.record_type {
        AlertRecordType::AlertEvent
        | AlertRecordType::LearnEvent
        | AlertRecordType::SyslogEvent
        | AlertRecordType::StorageResourceLearnEvent => font_awesome(cls, "info-circle"),
        x if is_cmd(x) => font_awesome(cls, "terminal"),
        _ => font_awesome(cls, "bell"),
    }
}

fn is_cmd(x: AlertRecordType) -> bool {
    match x {
        AlertRecordType::CommandRunningAlert
        | AlertRecordType::CommandSuccessfulAlert
        | AlertRecordType::CommandErroredAlert
        | AlertRecordType::CommandCancelledAlert => true,
        _ => false,
    }
}

fn alert_item_classes(alert: &Alert) -> (&str, &str, &str) {
    match (alert.record_type, alert.severity) {
        (AlertRecordType::CommandRunningAlert, _) => (C.border_gray_500, C.text_gray_500, C.bg_gray_400),
        (AlertRecordType::CommandSuccessfulAlert, _) => (C.border_green_500, C.text_green_500, C.bg_green_400),
        (AlertRecordType::CommandErroredAlert, _) => (C.border_red_500, C.text_red_500, C.bg_red_400),
        (AlertRecordType::CommandCancelledAlert, _) => (C.border_gray_500, C.text_gray_500, C.bg_gray_400),
        (_, AlertSeverity::DEBUG) => (C.border_gray_500, C.text_gray_500, C.bg_gray_400),
        (_, AlertSeverity::INFO) => (C.border_blue_500, C.text_blue_500, C.bg_blue_400),
        (_, AlertSeverity::WARNING) => (C.border_yellow_500, C.text_yellow_500, C.bg_yellow_400),
        (_, AlertSeverity::ERROR) => (C.border_red_500, C.text_red_500, C.bg_red_400),
        (_, AlertSeverity::CRITICAL) => (C.border_orange_500, C.text_orange_500, C.bg_orange_400),
    }
}

fn alert_item_view(
    all_locks: &Locks,
    sd: &date::Model,
    session: Option<&Session>,
    alert: &Alert,
    row: Option<&Row>,
) -> Node<Msg> {
    let (border_color, icon_color, bg_color) = alert_item_classes(alert);

    let is_active = alert.active.unwrap_or_default();

    div![
        class![
            border_color,
            bg_color => is_active,
            C.bg_menu => !is_active,
            C.border_l_8,
            C.gap_4,
            C.grid_cols_3,
            C.grid_flow_row,
            C.grid,
            C.items_center,
            C.mx_4,
            C.my_6,
            C.p_4,
            C.rounded,
            C.text_white,
        ],
        div![class![C.row_span_1, C.col_span_2], alert.message],
        div![
            class![C.row_span_1, C.col_span_1, C.grid, C.justify_end],
            alert_icon_view(alert).merge_attrs(class![icon_color])
        ],
        div![
            class![C.row_span_1, C.col_span_2, C.whitespace_no_wrap],
            "Started",
            " ",
            date_view(sd, &alert.begin)
        ],
        div![
            class![C.row_span_1, C.col_span_1, C.grid, C.justify_end],
            if let Some(row) = row {
                action_dropdown::unstyled_view(
                    alert.id,
                    &row.dropdown,
                    all_locks,
                    session,
                    class![C.bg_transparent, C.border, C.border_white],
                )
                .map_msg(|x| Msg::ActionDropdown(Box::new(x)))
            } else {
                empty![]
            }
        ],
        div![
            class![C.row_span_1, C.col_span_2, C.whitespace_no_wrap],
            if let Some(end) = alert.end.as_ref() {
                span!["Ended ", date_view(sd, end)]
            } else {
                empty![]
            }
        ],
        command_details_button(alert),
    ]
}

fn date_view<T>(sd: &date::Model, date: &str) -> Node<T> {
    match chrono::DateTime::parse_from_rfc3339(date) {
        Ok(d) => date::view(sd, &d),
        Err(e) => {
            error!(format!("could not parse the date: '{}': {}", date, e));
            plain![date.to_string()]
        }
    }
}

fn command_details_button(alert: &Alert) -> Node<Msg> {
    if !is_cmd(alert.record_type) {
        return empty![];
    }

    if let Some(id) = extract_id(&alert.alert_item) {
        button![
            class![
                C.border_white,
                C.border,
                C.focus__outline_none,
                C.font_bold,
                C.px_4,
                C.py_2,
                C.rounded,
                C.text_white
            ],
            simple_ev(Ev::Click, Msg::OpenCommandModal(id.parse().unwrap())),
            "Details",
        ]
    } else {
        empty![]
    }
}
<|endoftext|>


<commit_before>extern crate polydraw;

use polydraw::{Application, Renderer, Frame};
use polydraw::draw::RGB;

const DIV_PER_PIXEL: i64 = 1000;
const DOUBLE_PIXEL_AREA: i64 = DIV_PER_PIXEL * DIV_PER_PIXEL * 2;

#[inline]
fn to_px(v: i64) -> i64 {
   v / DIV_PER_PIXEL
}

#[inline]
fn from_px(v: i64) -> i64 {
   v as i64 * DIV_PER_PIXEL
}

struct CircleRenderer {
   center_x: i64,
   center_y: i64,
   radius: i64,
}

impl CircleRenderer {
   fn new() -> Self {
      let r = 300;
      CircleRenderer {
         center_x: from_px(r+100),
         center_y: from_px(r+100),
         radius: from_px(r),
      }
   }
}

impl Renderer for CircleRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      let color = RGB::new(127, 223, 255);

      frame.put_pixel(to_px(self.center_x) as i32, to_px(self.center_y) as i32, &color);
   }
}

fn main() {
   let mut renderer = CircleRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Circle")
      .run();
}
<commit_msg>Naive aliased circle filling<commit_after>extern crate polydraw;

use polydraw::{Application, Renderer, Frame};
use polydraw::draw::RGB;
use polydraw::geom::number::NumberOps;

const DIV_PER_PIXEL: i64 = 1000;

#[inline]
fn to_px(v: i64) -> i64 {
   v / DIV_PER_PIXEL
}

#[inline]
fn from_px(v: i64) -> i64 {
   v as i64 * DIV_PER_PIXEL
}

struct CircleRenderer {
   center_x: i64,
   center_y: i64,
   radius: i64,
}

impl CircleRenderer {
   fn new() -> Self {
      let r = 300;
      CircleRenderer {
         center_x: from_px(r+100),
         center_y: from_px(r+100),
         radius: from_px(r),
      }
   }
}

impl Renderer for CircleRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      let color = RGB::new(127, 223, 255);

      let center_x = to_px(self.center_x);
      let center_y = to_px(self.center_y);

      for y in 0..to_px(self.radius) + 1 {
         let y_world = from_px(y);
         let x_world = on_circle(self.radius, y_world);
         let x = to_px(x_world);

         let real_y = center_y + y;
         let bottom_y = center_y - y;

         for i in -x..x+1 {
            let real_x = center_x + i;
            frame.put_pixel(
               real_x as i32,
               real_y as i32,
               &color
            );
            frame.put_pixel(
               real_x as i32,
               bottom_y as i32,
               &color
            );
         }
      }
   }
}

fn on_circle(radius: i64, coord: i64) -> i64 {
   (radius.pow(2) - coord.pow(2)).sqrt()
}

fn main() {
   let mut renderer = CircleRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Circle")
      .run();
}
<|endoftext|>


<commit_before>use turtle::{Angle, Distance, Drawing, Point, Size, Turtle};

trait Rotate {
    fn rot(&self, angle: Angle) -> Self;
}

impl Rotate for Point {
    fn rot(&self, angle: Angle) -> Self {
        let (sin_angle, cos_angle) = angle.sin_cos();
        [
            self.x * cos_angle - self.y * sin_angle,
            self.x * sin_angle + self.y * cos_angle,
        ]
        .into()
    }
}

trait CubicBezier {
    const DEFAULT_SAMPLES: usize = 100;

    fn bezier_abs_pr(&mut self, samples: usize, points: [Point; 4]);
    fn bezier_rel_pr(&mut self, samples: usize, rel_points: [Point; 3]);

    fn bezier_abs(&mut self, points: [Point; 4]) {
        self.bezier_abs_pr(Self::DEFAULT_SAMPLES, points)
    }

    fn bezier_rel(&mut self, rel_points: [Point; 3]) {
        self.bezier_rel_pr(Self::DEFAULT_SAMPLES, rel_points)
    }

    fn curve_at(t: f64, points: [Point; 4]) -> Point {
        (1.0 - t).powi(3) * points[0]
            + 3.0 * (1.0 - t).powi(2) * t * points[1]
            + 3.0 * (1.0 - t) * t.powi(2) * points[2]
            + t.powi(3) * points[3]
    }
}

impl CubicBezier for Turtle {
    fn bezier_abs_pr(&mut self, samples: usize, points: [Point; 4]) {
        (0..=samples)
            .map(|i| i as f64 / samples as f64)
            .map(|t| Self::curve_at(t, points))
            .for_each(|point| {
                self.turn_towards(point);
                self.go_to(point);
            })
    }

    fn bezier_rel_pr(&mut self, samples: usize, rel_points: [Point; 3]) {
        let pos = self.position();
        self.bezier_abs_pr(
            samples,
            [
                pos,
                pos + rel_points[0],
                pos + rel_points[1],
                pos + rel_points[2],
            ],
        )
    }
}

const FRONT_SHELL_COLOR: &str = "#f74c00";
const BACK_SHELL_COLOR: &str = "#a52b00";
const PUPIL_COLOR: &str = "#ffffff";
const MOUTH_COLOR: &str = "#000000";
const ORIGINAL_SIZE: Size = Size {
    width: 1200,
    height: 800,
};

fn adapt_point(point: impl Into<Point>, size: Size) -> Point {
    let point = point.into();
    Point {
        x: size.width as f64 * point.x / ORIGINAL_SIZE.width as f64,
        y: -(size.height as f64) * point.y / ORIGINAL_SIZE.height as f64,
    }
}

fn rel_points(abs_points: [Point; 4]) -> [Point; 3] {
    [
        abs_points[1] - abs_points[0],
        abs_points[2] - abs_points[0],
        abs_points[3] - abs_points[0],
    ]
}

fn adapt_distance(distance: Distance, angle: Angle, size: Size) -> Distance {
    ((distance * angle.cos() * size.width as f64 / ORIGINAL_SIZE.width as f64).powi(2)
        + (distance * angle.sin() * size.height as f64 / ORIGINAL_SIZE.height as f64).powi(2))
    .sqrt()
}

fn main() {
    let mut drawing = Drawing::new();
    let size = drawing.size();
    drawing.set_center([size.width as f64 / 2.0, -(size.height as f64) / 2.0]);

    let mut turtle = drawing.add_turtle();
    turtle.use_radians();
    turtle.pen_up();

    let rp = rel_points;
    let ap = |point| adapt_point(point, size);
    let ad = |distance, angle| adapt_distance(distance, angle, size);

    let start_point = ap([240.0, 504.0]);
    turtle.set_fill_color(BACK_SHELL_COLOR);
    turtle.set_speed("instant");
    turtle.turn_towards(start_point);
    turtle.go_to(start_point);
    turtle.set_speed("faster");
    turtle.begin_fill();

    let start_heading = (180.0 + 32.01f64).to_radians();
    turtle.set_heading(start_heading);
    turtle.forward(ad(18.9, start_heading));
    turtle.bezier_rel(rp([
        ap([223.64, 514.18]),
        ap([222.18, 525.09]),
        ap([288.00, 597.09]),
        ap([323.94, 645.06]),
    ]));
    turtle.bezier_rel(rp([
        ap([323.91, 645.18]),
        ap([324.00, 623.09]),
        ap([283.27, 565.27]),
        ap([270.69, 529.94]),
    ]));
    turtle.bezier_rel(rp([
        ap([270.75, 529.94]),
        ap([444.75, 621.50]),
        ap([826.25, 622.50]),
        ap([973.09, 515.22]),
    ]));
    turtle.bezier_rel(rp([
        ap([973.12, 515.25]),
        ap([965.45, 552.18]),
        ap([923.09, 619.45]),
        ap([922.09, 646.52]),
    ]));
    turtle.bezier_rel(rp([
        ap([922.38, 647.00]),
        ap([931.09, 631.09]),
        ap([988.91, 554.55]),
        ap([1008.00, 517.12]),
    ]));
    let middle_curve_part1 = rp([
        ap([1008.12, 517.06]),
        ap([979.25, 500.88]),
        ap([960.12, 507.19]),
        ap([946.69, 510.31]),
    ]);
    turtle.bezier_rel(middle_curve_part1);
    let middle_curve_part2 = rp([
        ap([946.66, 510.41]),
        ap([750.73, 606.91]),
        ap([472.55, 603.45]),
        ap([239.57, 505.39]),
    ]);
    turtle.bezier_rel(middle_curve_part2);

    turtle.end_fill();
    turtle.set_fill_color(FRONT_SHELL_COLOR);
    turtle.begin_fill();

    turtle.bezier_rel(rp([
        ap([239.45, 504.36]),
        ap([233.00, 508.18]),
        ap([213.45, 519.82]),
        ap([212.50, 524.44]),
    ]));
    turtle.bezier_rel(rp([
        ap([212.25, 524.44]),
        ap([215.00, 570.50]),
        ap([300.00, 657.50]),
        ap([304.52, 700.83]),
    ]));
    turtle.bezier_rel(rp([
        ap([303.56, 702.56]),
        ap([206.50, 599.75]),
        ap([133.25, 541.75]),
        ap([138.00, 522.82]),
    ]));
    turtle.bezier_rel(rp([
        ap([138.00, 523.18]),
        ap([137.82, 511.73]),
        ap([145.55, 510.64]),
        ap([176.00, 476.00]),
    ]));
    turtle.bezier_rel(rp([
        ap([175.64, 475.55]),
        ap([138.73, 455.36]),
        ap([111.09, 430.55]),
        ap([103.73, 408.91]),
    ]));
    turtle.bezier_rel(rp([
        ap([103.91, 409.55]),
        ap([-21.00, 349.50]),
        ap([5.00, 282.50]),
        ap([52.00, 244.12]),
    ]));
    turtle.bezier_rel(rp([
        ap([52.69, 244.19]),
        ap([59.00, 289.00]),
        ap([83.12, 323.00]),
        ap([109.56, 344.59]),
    ]));
    let left_claw_heading = (180.0 - 82.13f64).to_radians();
    turtle.set_heading(left_claw_heading);
    turtle.forward(ad(124.2, turtle.heading()));
    turtle.bezier_rel(rp([
        ap([93.13, 221.13]),
        ap([163.25, 250.75]),
        ap([216.25, 316.75]),
        ap([148.35, 405.39]),
    ]));
    turtle.bezier_rel(rp([
        ap([148.52, 405.43]),
        ap([160.27, 422.64]),
        ap([185.00, 435.45]),
        ap([207.04, 443.65]),
    ]));
    let left_claw_heading = 45f64.to_radians();
    turtle.set_heading(left_claw_heading);
    turtle.forward(ad(12.7, turtle.heading()));
}
<commit_msg>Add relative to heading and position Bézier method<commit_after>use turtle::{Angle, Distance, Drawing, Point, Size, Turtle};

trait Rotate {
    fn rot(&self, angle: Angle) -> Self;
}

impl Rotate for Point {
    fn rot(&self, angle: Angle) -> Self {
        let (sin_angle, cos_angle) = angle.sin_cos();
        [
            self.x * cos_angle - self.y * sin_angle,
            self.x * sin_angle + self.y * cos_angle,
        ]
        .into()
    }
}

trait CubicBezier {
    const DEFAULT_SAMPLES: usize = 100;

    fn bezier_abs_pr(&mut self, samples: usize, points: [Point; 4]);
    fn bezier_rel_pr(&mut self, samples: usize, rel_points: [Point; 3]);
    fn bezier_rel_head_pr(&mut self, samples: usize, rel_points: [Point; 3]);

    fn bezier_abs(&mut self, points: [Point; 4]) {
        self.bezier_abs_pr(Self::DEFAULT_SAMPLES, points)
    }

    fn bezier_rel(&mut self, rel_points: [Point; 3]) {
        self.bezier_rel_pr(Self::DEFAULT_SAMPLES, rel_points)
    }

    fn bezier_rel_head(&mut self, rel_points: [Point; 3]) {
        self.bezier_rel_head_pr(Self::DEFAULT_SAMPLES, rel_points)
    }

    fn curve_at(t: f64, points: [Point; 4]) -> Point {
        (1.0 - t).powi(3) * points[0]
            + 3.0 * (1.0 - t).powi(2) * t * points[1]
            + 3.0 * (1.0 - t) * t.powi(2) * points[2]
            + t.powi(3) * points[3]
    }
}

impl CubicBezier for Turtle {
    fn bezier_abs_pr(&mut self, samples: usize, points: [Point; 4]) {
        (0..=samples)
            .map(|i| i as f64 / samples as f64)
            .map(|t| Self::curve_at(t, points))
            .for_each(|point| {
                self.turn_towards(point);
                self.go_to(point);
            })
    }

    fn bezier_rel_pr(&mut self, samples: usize, rel_points: [Point; 3]) {
        let pos = self.position();
        self.bezier_abs_pr(
            samples,
            [
                pos,
                pos + rel_points[0],
                pos + rel_points[1],
                pos + rel_points[2],
            ],
        )
    }

    fn bezier_rel_head_pr(&mut self, samples: usize, rel_points: [Point; 3]) {
        let pos = self.position();
        let rot_angle = self.heading() - rel_points[0].atan2();
        self.bezier_abs_pr(
            samples,
            [
                pos,
                pos + rel_points[0].rot(rot_angle),
                pos + rel_points[1].rot(rot_angle),
                pos + rel_points[2].rot(rot_angle),
            ],
        )
    }
}

const FRONT_SHELL_COLOR: &str = "#f74c00";
const BACK_SHELL_COLOR: &str = "#a52b00";
const PUPIL_COLOR: &str = "#ffffff";
const MOUTH_COLOR: &str = "#000000";
const ORIGINAL_SIZE: Size = Size {
    width: 1200,
    height: 800,
};

fn adapt_point(point: impl Into<Point>, size: Size) -> Point {
    let point = point.into();
    Point {
        x: size.width as f64 * point.x / ORIGINAL_SIZE.width as f64,
        y: -(size.height as f64) * point.y / ORIGINAL_SIZE.height as f64,
    }
}

fn rel_points(abs_points: [Point; 4]) -> [Point; 3] {
    [
        abs_points[1] - abs_points[0],
        abs_points[2] - abs_points[0],
        abs_points[3] - abs_points[0],
    ]
}

fn adapt_distance(distance: Distance, angle: Angle, size: Size) -> Distance {
    ((distance * angle.cos() * size.width as f64 / ORIGINAL_SIZE.width as f64).powi(2)
        + (distance * angle.sin() * size.height as f64 / ORIGINAL_SIZE.height as f64).powi(2))
    .sqrt()
}

fn main() {
    let mut drawing = Drawing::new();
    let size = drawing.size();
    drawing.set_center([size.width as f64 / 2.0, -(size.height as f64) / 2.0]);

    let mut turtle = drawing.add_turtle();
    turtle.use_radians();
    turtle.pen_up();

    let rp = rel_points;
    let ap = |point| adapt_point(point, size);
    let ad = |distance, angle| adapt_distance(distance, angle, size);

    let start_point = ap([240.0, 504.0]);
    turtle.set_fill_color(BACK_SHELL_COLOR);
    turtle.set_speed("instant");
    turtle.turn_towards(start_point);
    turtle.go_to(start_point);
    turtle.set_speed("faster");
    turtle.begin_fill();

    let start_heading = (180.0 + 32.01f64).to_radians();
    turtle.set_heading(start_heading);
    turtle.forward(ad(18.9, start_heading));
    turtle.bezier_rel(rp([
        ap([223.64, 514.18]),
        ap([222.18, 525.09]),
        ap([288.00, 597.09]),
        ap([323.94, 645.06]),
    ]));
    turtle.bezier_rel(rp([
        ap([323.91, 645.18]),
        ap([324.00, 623.09]),
        ap([283.27, 565.27]),
        ap([270.69, 529.94]),
    ]));
    turtle.bezier_rel(rp([
        ap([270.75, 529.94]),
        ap([444.75, 621.50]),
        ap([826.25, 622.50]),
        ap([973.09, 515.22]),
    ]));
    turtle.bezier_rel(rp([
        ap([973.12, 515.25]),
        ap([965.45, 552.18]),
        ap([923.09, 619.45]),
        ap([922.09, 646.52]),
    ]));
    turtle.bezier_rel(rp([
        ap([922.38, 647.00]),
        ap([931.09, 631.09]),
        ap([988.91, 554.55]),
        ap([1008.00, 517.12]),
    ]));
    let middle_curve_part1 = rp([
        ap([1008.12, 517.06]),
        ap([979.25, 500.88]),
        ap([960.12, 507.19]),
        ap([946.69, 510.31]),
    ]);
    turtle.bezier_rel(middle_curve_part1);
    let middle_curve_part2 = rp([
        ap([946.66, 510.41]),
        ap([750.73, 606.91]),
        ap([472.55, 603.45]),
        ap([239.57, 505.39]),
    ]);
    turtle.bezier_rel(middle_curve_part2);

    turtle.end_fill();
    turtle.set_fill_color(FRONT_SHELL_COLOR);
    turtle.begin_fill();

    turtle.bezier_rel(rp([
        ap([239.45, 504.36]),
        ap([233.00, 508.18]),
        ap([213.45, 519.82]),
        ap([212.50, 524.44]),
    ]));
    turtle.bezier_rel(rp([
        ap([212.25, 524.44]),
        ap([215.00, 570.50]),
        ap([300.00, 657.50]),
        ap([304.52, 700.83]),
    ]));
    turtle.bezier_rel(rp([
        ap([303.56, 702.56]),
        ap([206.50, 599.75]),
        ap([133.25, 541.75]),
        ap([138.00, 522.82]),
    ]));
    turtle.bezier_rel(rp([
        ap([138.00, 523.18]),
        ap([137.82, 511.73]),
        ap([145.55, 510.64]),
        ap([176.00, 476.00]),
    ]));
    turtle.bezier_rel(rp([
        ap([175.64, 475.55]),
        ap([138.73, 455.36]),
        ap([111.09, 430.55]),
        ap([103.73, 408.91]),
    ]));
    turtle.bezier_rel(rp([
        ap([103.91, 409.55]),
        ap([-21.00, 349.50]),
        ap([5.00, 282.50]),
        ap([52.00, 244.12]),
    ]));
    turtle.bezier_rel(rp([
        ap([52.69, 244.19]),
        ap([59.00, 289.00]),
        ap([83.12, 323.00]),
        ap([109.56, 344.59]),
    ]));
    let left_claw_heading = (180.0 - 82.13f64).to_radians();
    turtle.set_heading(left_claw_heading);
    turtle.forward(ad(124.2, turtle.heading()));
    turtle.bezier_rel(rp([
        ap([93.13, 221.13]),
        ap([163.25, 250.75]),
        ap([216.25, 316.75]),
        ap([148.35, 405.39]),
    ]));
    turtle.bezier_rel(rp([
        ap([148.52, 405.43]),
        ap([160.27, 422.64]),
        ap([185.00, 435.45]),
        ap([207.04, 443.65]),
    ]));
    let left_claw_heading = 45f64.to_radians();
    turtle.set_heading(left_claw_heading);
    turtle.forward(ad(12.7, turtle.heading()));
}
<|endoftext|>