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

use std::convert::TryFrom;

use serde::{Deserialize, Serialize};
use slog::{info, o, Logger};

use crate::extensions::filter_registry::{
    CreateFilterArgs, Error, FilterFactory, ReadContext, ReadResponse, WriteContext, WriteResponse,
};
use crate::extensions::Filter;

/// Protobuf config for this filter.
mod quilkin {
    pub(crate) mod extensions {
        pub(crate) mod filters {
            pub(crate) mod debug {
                pub(crate) mod v1alpha1 {
                    #![doc(hidden)]
                    tonic::include_proto!("quilkin.extensions.filters.debug.v1alpha1");
                }
            }
        }
    }
}
use self::quilkin::extensions::filters::debug::v1alpha1::Debug as ProtoDebug;
use crate::extensions::filters::ConvertProtoConfigError;

/// Debug logs all incoming and outgoing packets
pub struct Debug {
    log: Logger,
}

impl Debug {
    /// Constructor for the Debug. Pass in a "id" to append a string to your log messages from this
    /// Filter.
    fn new(base: &Logger, id: Option<String>) -> Self {
        let log = match id {
            None => base.new(o!("source" => "extensions::Debug")),
            Some(id) => base.new(o!("source" => "extensions::Debug", "id" => id)),
        };

        Debug { log }
    }
}

/// A Debug filter's configuration.
#[derive(Serialize, Deserialize, Debug)]
struct Config {
    id: Option<String>,
}

impl TryFrom<ProtoDebug> for Config {
    type Error = ConvertProtoConfigError;

    fn try_from(p: ProtoDebug) -> Result<Self, Self::Error> {
        Ok(Config { id: p.id })
    }
}

/// Factory for the Debug
pub struct DebugFactory {
    log: Logger,
}

impl DebugFactory {
    pub fn new(base: &Logger) -> Self {
        DebugFactory { log: base.clone() }
    }
}

impl FilterFactory for DebugFactory {
    fn name(&self) -> String {
        "quilkin.extensions.filters.debug.v1alpha1.Debug".into()
    }

    fn create_filter(&self, args: CreateFilterArgs) -> Result<Box<dyn Filter>, Error> {
        let config: Option<Config> = args
            .config
            .map(|config| config.deserialize::<Config, ProtoDebug>(self.name().as_str()))
            .transpose()?;
        Ok(Box::new(Debug::new(
            &self.log,
            config.and_then(|cfg| cfg.id),
        )))
    }
}

impl Filter for Debug {
    fn read(&self, ctx: ReadContext) -> Option<ReadResponse> {
        info!(self.log, "on local receive"; "from" => ctx.from, "contents" => packet_to_string(ctx.contents.clone()));
        Some(ctx.into())
    }

    fn write(&self, ctx: WriteContext) -> Option<WriteResponse> {
        info!(self.log, "Received endpoint packet"; "endpoint" => ctx.endpoint.address,
        "from" => ctx.from,
        "to" => ctx.to,
        "contents" => packet_to_string(ctx.contents.clone()));
        Some(ctx.into())
    }
}

/// packet_to_string takes the content, and attempts to convert it to a string.
/// Returns a string of "error decoding packet" on failure.
fn packet_to_string(contents: Vec<u8>) -> String {
    match String::from_utf8(contents) {
        Ok(str) => str,
        Err(_) => String::from("error decoding packet"),
    }
}

#[cfg(test)]
mod tests {
    use serde_yaml::Mapping;
    use serde_yaml::Value;

    use crate::test_utils::{assert_filter_read_no_change, assert_write_no_change, logger};

    use super::*;
    use prometheus::Registry;

    #[test]
    fn read() {
        let df = Debug::new(&logger(), None);
        assert_filter_read_no_change(&df);
    }

    #[test]
    fn write() {
        let df = Debug::new(&logger(), None);
        assert_write_no_change(&df);
    }

    #[test]
    fn from_config_with_id() {
        let log = logger();
        let mut map = Mapping::new();
        let factory = DebugFactory::new(&log);

        map.insert(Value::from("id"), Value::from("name"));
        assert!(factory
            .create_filter(CreateFilterArgs::fixed(
                Registry::default(),
                Some(&Value::Mapping(map)),
            ))
            .is_ok());
    }

    #[test]
    fn from_config_without_id() {
        let log = logger();
        let mut map = Mapping::new();
        let factory = DebugFactory::new(&log);

        map.insert(Value::from("id"), Value::from("name"));
        assert!(factory
            .create_filter(CreateFilterArgs::fixed(
                Registry::default(),
                Some(&Value::Mapping(map)),
            ))
            .is_ok());
    }

    #[test]
    fn from_config_should_error() {
        let log = logger();
        let mut map = Mapping::new();
        let factory = DebugFactory::new(&log);

        map.insert(Value::from("id"), Value::Sequence(vec![]));
        assert!(factory
            .create_filter(CreateFilterArgs::fixed(
                Registry::default(),
                Some(&Value::Mapping(map))
            ))
            .is_err());
    }
}
<commit_msg>Debug Filter: Capitalise log statement. (#223)<commit_after>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::convert::TryFrom;

use serde::{Deserialize, Serialize};
use slog::{info, o, Logger};

use crate::extensions::filter_registry::{
    CreateFilterArgs, Error, FilterFactory, ReadContext, ReadResponse, WriteContext, WriteResponse,
};
use crate::extensions::Filter;

/// Protobuf config for this filter.
mod quilkin {
    pub(crate) mod extensions {
        pub(crate) mod filters {
            pub(crate) mod debug {
                pub(crate) mod v1alpha1 {
                    #![doc(hidden)]
                    tonic::include_proto!("quilkin.extensions.filters.debug.v1alpha1");
                }
            }
        }
    }
}
use self::quilkin::extensions::filters::debug::v1alpha1::Debug as ProtoDebug;
use crate::extensions::filters::ConvertProtoConfigError;

/// Debug logs all incoming and outgoing packets
pub struct Debug {
    log: Logger,
}

impl Debug {
    /// Constructor for the Debug. Pass in a "id" to append a string to your log messages from this
    /// Filter.
    fn new(base: &Logger, id: Option<String>) -> Self {
        let log = match id {
            None => base.new(o!("source" => "extensions::Debug")),
            Some(id) => base.new(o!("source" => "extensions::Debug", "id" => id)),
        };

        Debug { log }
    }
}

/// A Debug filter's configuration.
#[derive(Serialize, Deserialize, Debug)]
struct Config {
    id: Option<String>,
}

impl TryFrom<ProtoDebug> for Config {
    type Error = ConvertProtoConfigError;

    fn try_from(p: ProtoDebug) -> Result<Self, Self::Error> {
        Ok(Config { id: p.id })
    }
}

/// Factory for the Debug
pub struct DebugFactory {
    log: Logger,
}

impl DebugFactory {
    pub fn new(base: &Logger) -> Self {
        DebugFactory { log: base.clone() }
    }
}

impl FilterFactory for DebugFactory {
    fn name(&self) -> String {
        "quilkin.extensions.filters.debug.v1alpha1.Debug".into()
    }

    fn create_filter(&self, args: CreateFilterArgs) -> Result<Box<dyn Filter>, Error> {
        let config: Option<Config> = args
            .config
            .map(|config| config.deserialize::<Config, ProtoDebug>(self.name().as_str()))
            .transpose()?;
        Ok(Box::new(Debug::new(
            &self.log,
            config.and_then(|cfg| cfg.id),
        )))
    }
}

impl Filter for Debug {
    fn read(&self, ctx: ReadContext) -> Option<ReadResponse> {
        info!(self.log, "Read filter event"; "from" => ctx.from, "contents" => packet_to_string(ctx.contents.clone()));
        Some(ctx.into())
    }

    fn write(&self, ctx: WriteContext) -> Option<WriteResponse> {
        info!(self.log, "Write filter event"; "endpoint" => ctx.endpoint.address,
        "from" => ctx.from,
        "to" => ctx.to,
        "contents" => packet_to_string(ctx.contents.clone()));
        Some(ctx.into())
    }
}

/// packet_to_string takes the content, and attempts to convert it to a string.
/// Returns a string of "error decoding packet" on failure.
fn packet_to_string(contents: Vec<u8>) -> String {
    match String::from_utf8(contents) {
        Ok(str) => str,
        Err(_) => String::from("error decoding packet"),
    }
}

#[cfg(test)]
mod tests {
    use serde_yaml::Mapping;
    use serde_yaml::Value;

    use crate::test_utils::{assert_filter_read_no_change, assert_write_no_change, logger};

    use super::*;
    use prometheus::Registry;

    #[test]
    fn read() {
        let df = Debug::new(&logger(), None);
        assert_filter_read_no_change(&df);
    }

    #[test]
    fn write() {
        let df = Debug::new(&logger(), None);
        assert_write_no_change(&df);
    }

    #[test]
    fn from_config_with_id() {
        let log = logger();
        let mut map = Mapping::new();
        let factory = DebugFactory::new(&log);

        map.insert(Value::from("id"), Value::from("name"));
        assert!(factory
            .create_filter(CreateFilterArgs::fixed(
                Registry::default(),
                Some(&Value::Mapping(map)),
            ))
            .is_ok());
    }

    #[test]
    fn from_config_without_id() {
        let log = logger();
        let mut map = Mapping::new();
        let factory = DebugFactory::new(&log);

        map.insert(Value::from("id"), Value::from("name"));
        assert!(factory
            .create_filter(CreateFilterArgs::fixed(
                Registry::default(),
                Some(&Value::Mapping(map)),
            ))
            .is_ok());
    }

    #[test]
    fn from_config_should_error() {
        let log = logger();
        let mut map = Mapping::new();
        let factory = DebugFactory::new(&log);

        map.insert(Value::from("id"), Value::Sequence(vec![]));
        assert!(factory
            .create_filter(CreateFilterArgs::fixed(
                Registry::default(),
                Some(&Value::Mapping(map))
            ))
            .is_err());
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;

#[macro_use]
mod spec;
mod block;
mod view;
mod config;

use std::borrow::Borrow;
use std::ops::Deref;

use time::Timespec;

use ::crypto::{Hash, hash};
use ::messages::{Precommit, Message, ConfigMessage, ServiceTx, ConfigPropose, ConfigVote, AnyTx};

use ::storage::{StorageValue, Patch, Database, Fork, Error, Map, List};

pub use self::block::Block;
pub use self::view::View;

pub use self::config::{StoredConfiguration, ConsensusCfg};

pub use self::view::ConfigurationData;

pub trait Blockchain: Sized + Clone + Send + Sync + 'static
    where Self: Deref<Target = <Self as Blockchain>::Database>
{
    type View: View<<<Self as Blockchain>::Database as Database>::Fork, Transaction=Self::Transaction>;
    type Database: Database;
    type Transaction: Message + StorageValue;

    fn last_hash(&self) -> Result<Option<Hash>, Error> {
        self.view().heights().last()
    }

    fn last_block(&self) -> Result<Option<Block>, Error> {
        let view = self.view();
        Ok(match view.heights().last()? {
            Some(hash) => Some(view.blocks().get(&hash)?.unwrap()),
            None => None,
        })
    }

    fn verify_tx(tx: &Self::Transaction) -> bool;
    fn state_hash(fork: &Self::View) -> Result<Hash, Error>;
    fn execute(fork: &Self::View, tx: &Self::Transaction) -> Result<(), Error>;
    // FIXME make private
    fn execute_service_tx(view: &Self::View, tx: &ServiceTx) -> Result<(), Error> {
        match *tx {
            ServiceTx::ConfigChange(ref config_message) => {
                Ok(Self::execute_config_change(view, config_message))
            }
        }
    }

    // TODO use Iterator to avoid memory allocations?
    fn create_patch(&self,
                    height: u64,
                    round: u32,
                    time: Timespec,
                    txs: &[(Hash, AnyTx<Self::Transaction>)])
                    -> Result<(Hash, Vec<Hash>, Patch), Error> {
        // Get last hash
        let last_hash = self.last_hash()?.unwrap_or_else(|| hash(&[]));
        // Create fork
        let fork = self.view();
        // Save & execute transactions
        let mut tx_hashes = Vec::new();
        for &(hash, ref tx) in txs {

            match *tx {
                AnyTx::Application(ref tx) => Self::execute(&fork, tx)?,
                AnyTx::Service(ref tx) => Self::execute_service_tx(&fork, tx)?,
            }
            fork.transactions()
                .put(&hash, tx.clone())
                .unwrap();
            fork.block_txs(height)
                .append(hash)
                .unwrap();
            tx_hashes.push(hash);
        }
        // Get tx hash
        let tx_hash = fork.block_txs(height).root_hash()?;
        // Get state hash
        let state_hash = Self::state_hash(&fork)?;
        // Create block
        let block = Block::new(height, round, time, &last_hash, &tx_hash, &state_hash);
        // Eval block hash
        let block_hash = block.hash();
        // Update height
        // TODO: check that height == propose.height
        fork.heights().append(block_hash).is_ok();
        // Save block
        fork.blocks().put(&block_hash, block).is_ok();
        Ok((block_hash, tx_hashes, fork.changes()))
    }

    fn execute_config_change(view: &Self::View, config_message: &ConfigMessage) {
        match *config_message {
            ConfigMessage::ConfigPropose(ref config_propose_tx) => {
                Self::handle_config_propose(view, config_propose_tx);
            }
            ConfigMessage::ConfigVote(ref config_vote_tx) => {
                Self::handle_config_vote(view, config_vote_tx);
            }
        }
    }

    fn last_block_(view: &Self::View) -> Result<Option<Block>, Error> {
        Ok(match view.heights().last()? {
            Some(hash) => Some(view.blocks().get(&hash)?.unwrap()),
            None => None,
        })
    }
    fn get_height(view: &Self::View) -> u64 {
        if let Ok(Some(last_block)) = Self::last_block_(view){
            return last_block.height() + 1;
        }
        0
    }

    fn get_actual_configuration(view: &Self::View) -> Option<StoredConfiguration> {

        let h = Self::get_height(view);

        let heights = view.configs_heights();

        if let Ok(height_values) = heights.values() {

            if let Some(idx) = height_values.into_iter()
                .rposition(|r| u64::from(r) <= h) {
                if let Ok(Some(height)) = heights.get(idx as u64) {
                    return Self::get_configuration_at_height(view, height.into());
                }
            }
        }
        None
    }

    fn get_configuration_at_height(view: &Self::View, height: u64) -> Option<StoredConfiguration> {
        let configs = view.configs();
        if let Ok(Some(config)) = configs.get(&height.into()) {
            match StoredConfiguration::deserialize(&config) {
                Ok(configuration) => {
                    return Some(configuration);
                }
                Err(_) => {
                    error!("Can't parse found configuration at height: {}", height);
                }
            }
        }
        None
    }

    fn handle_config_propose(view: &Self::View, config_propose: &ConfigPropose) {

        if let Some(config) = Self::get_actual_configuration(view) {
            if !config.validators.contains(config_propose.from()) {
                error!("ConfigPropose from unknown validator: {:?}",
                       config_propose.from());
                return;
            }

            let hash = <ConfigPropose as Message>::hash(config_propose);
            if view.config_proposes().get(&hash).unwrap().is_some() {
                error!("Received config_propose has already been handled, msg={:?}",
                       config_propose);
                return;
            }

            trace!("Handle ConfigPropose");
            let _ = view.config_proposes().put(&hash, config_propose.clone());
        }
    }

    fn handle_config_vote(view: &Self::View, config_vote: &ConfigVote) {

        if let Some(config) = Self::get_actual_configuration(view) {

            if !config.validators.contains(config_vote.from()) {
                error!("ConfigVote from unknown validator: {:?}",
                       config_vote.from());
                return;
            }

            if view.config_proposes().get(config_vote.hash_propose()).unwrap().is_some() {
                error!("Received config_vote for unknown transaciton, msg={:?}",
                       config_vote);
                return;
            }

            if let Some(vote) = view.config_votes().get(config_vote.from()).unwrap() {
                if vote.seed() != config_vote.seed() - 1 {
                    error!("Received config_vote with wrong seed, msg={:?}",
                           config_vote);
                    return;
                }
            }

            let msg = config_vote.clone();
            let _ = view.config_votes().put(msg.from(), config_vote.clone());

            let mut votes_count = 0;
            for pub_key in config.validators.clone() {
                if let Some(vote) = view.config_votes().get(&pub_key).unwrap() {
                    if !vote.revoke() {
                        votes_count += 1;
                    }
                }
            }

            if votes_count >= 2 / 3 * config.validators.len() {
                if let Some(config_propose) = view.config_proposes()
                    .get(config_vote.hash_propose())
                    .unwrap() {
                    let height_bytecode = config_propose.actual_from_height().into();
                    view.configs().put(&height_bytecode, config_propose.config().to_vec()).unwrap();
                    view.configs_heights().append(height_bytecode).unwrap();
                    // TODO: clear storages
                }
            }
        }
    }

    fn commit<'a, I: Iterator<Item = &'a Precommit>>(&self,
                                                     block_hash: Hash,
                                                     patch: &Patch,
                                                     precommits: I)
                                                     -> Result<(), Error> {
        let patch = {
            let view = self.view();
            view.merge(patch);

            for precommit in precommits {
                view.precommits(&block_hash).append(precommit.clone())?;
            }

            view.changes()
        };

        self.merge(&patch)
    }

    fn view(&self) -> Self::View {
        Self::View::from_fork(self.borrow().fork())
    }

    fn merge(&self, patch: &Patch) -> Result<(), Error> {
        self.deref().merge(patch)
    }
}
<commit_msg>Test<commit_after>extern crate serde_json;

#[macro_use]
mod spec;
mod block;
mod view;
mod config;

use std::borrow::Borrow;
use std::ops::Deref;

use time::Timespec;

use ::crypto::{Hash, hash};
use ::messages::{Precommit, Message, ConfigMessage, ServiceTx, ConfigPropose, ConfigVote, AnyTx};

use ::storage::{StorageValue, Patch, Database, Fork, Error, Map, List};

pub use self::block::Block;
pub use self::view::View;

pub use self::config::{StoredConfiguration, ConsensusCfg};

pub use self::view::ConfigurationData;

pub trait Blockchain: Sized + Clone + Send + Sync + 'static
    where Self: Deref<Target = <Self as Blockchain>::Database>
{
    type View: View<<<Self as Blockchain>::Database as Database>::Fork, Transaction=Self::Transaction>;
    type Database: Database;
    type Transaction: Message + StorageValue;

    fn last_hash(&self) -> Result<Option<Hash>, Error> {
        self.view().heights().last()
    }

    fn last_block(&self) -> Result<Option<Block>, Error> {
        let view = self.view();
        Ok(match view.heights().last()? {
            Some(hash) => Some(view.blocks().get(&hash)?.unwrap()),
            None => None,
        })
    }

    fn verify_tx(tx: &Self::Transaction) -> bool;
    fn state_hash(fork: &Self::View) -> Result<Hash, Error>;
    fn execute(fork: &Self::View, tx: &Self::Transaction) -> Result<(), Error>;
    // FIXME make private
    fn execute_service_tx(view: &Self::View, tx: &ServiceTx) -> Result<(), Error> {
        match *tx {
            ServiceTx::ConfigChange(ref config_message) => {
                Ok(Self::execute_config_change(view, config_message))
            }
        }
    }

    // TODO use Iterator to avoid memory allocations?
    fn create_patch(&self,
                    height: u64,
                    round: u32,
                    time: Timespec,
                    txs: &[(Hash, AnyTx<Self::Transaction>)])
                    -> Result<(Hash, Vec<Hash>, Patch), Error> {
        // Get last hash
        let last_hash = self.last_hash()?.unwrap_or_else(|| hash(&[]));
        // Create fork
        let fork = self.view();
        // Save & execute transactions
        let mut tx_hashes = Vec::new();
        for &(hash, ref tx) in txs {

            match *tx {
                AnyTx::Application(ref tx) => Self::execute(&fork, tx)?,
                AnyTx::Service(ref tx) => Self::execute_service_tx(&fork, tx)?,
            }
            fork.transactions()
                .put(&hash, tx.clone())
                .unwrap();
            fork.block_txs(height)
                .append(hash)
                .unwrap();
            tx_hashes.push(hash);
        }
        // Get tx hash
        let tx_hash = fork.block_txs(height).root_hash()?;
        // Get state hash
        let state_hash = Self::state_hash(&fork)?;
        // Create block
        let block = Block::new(height, round, time, &last_hash, &tx_hash, &state_hash);
        // Eval block hash
        let block_hash = block.hash();
        // Update height
        // TODO: check that height == propose.height
        fork.heights().append(block_hash).is_ok();
        // Save block
        fork.blocks().put(&block_hash, block).is_ok();
        Ok((block_hash, tx_hashes, fork.changes()))
    }

    fn execute_config_change(view: &Self::View, config_message: &ConfigMessage) {
        match *config_message {
            ConfigMessage::ConfigPropose(ref config_propose_tx) => {
                Self::handle_config_propose(view, config_propose_tx);
            }
            ConfigMessage::ConfigVote(ref config_vote_tx) => {
                Self::handle_config_vote(view, config_vote_tx);
            }
        }
    }

    fn last_block_(view: &Self::View) -> Result<Option<Block>, Error> {
        Ok(match view.heights().last()? {
            Some(hash) => Some(view.blocks().get(&hash)?.unwrap()),
            None => None,
        })
    }
    fn get_height(view: &Self::View) -> u64 {
        if let Ok(Some(last_block)) = Self::last_block_(view){
            return last_block.height() + 1;
        }
        0
    }

    fn get_actual_configuration(view: &Self::View) -> Option<StoredConfiguration> {

        let h = Self::get_height(view);

        let heights = view.configs_heights();

        if let Ok(height_values) = heights.values() {

            if let Some(idx) = height_values.into_iter()
                .rposition(|r| u64::from(r) <= h) {
                if let Ok(Some(height)) = heights.get(idx as u64) {
                    return Self::get_configuration_at_height(view, height.into());
                }
            }
        }
        None
    }

    fn get_configuration_at_height(view: &Self::View, height: u64) -> Option<StoredConfiguration> {
        let configs = view.configs();
        if let Ok(Some(config)) = configs.get(&height.into()) {
            match StoredConfiguration::deserialize(&config) {
                Ok(configuration) => {
                    return Some(configuration);
                }
                Err(_) => {
                    error!("Can't parse found configuration at height: {}", height);
                }
            }
        }
        None
    }

    fn handle_config_propose(view: &Self::View, config_propose: &ConfigPropose) {

        if let Some(config) = Self::get_actual_configuration(view) {
            if !config.validators.contains(config_propose.from()) {
                error!("ConfigPropose from unknown validator: {:?}",
                       config_propose.from());
                return;
            }

            let hash = <ConfigPropose as Message>::hash(config_propose);
            if view.config_proposes().get(&hash).unwrap().is_some() {
                error!("Received config_propose has already been handled, msg={:?}",
                       config_propose);
                return;
            }

            trace!("Handle ConfigPropose");
            let _ = view.config_proposes().put(&hash, config_propose.clone());
        }
    }

    fn handle_config_vote(view: &Self::View, config_vote: &ConfigVote) {

        if let Some(config) = Self::get_actual_configuration(view) {

            if !config.validators.contains(config_vote.from()) {
                error!("ConfigVote from unknown validator: {:?}",
                    config_vote.from());
                return;
            }

            if view.config_proposes().get(config_vote.hash_propose()).unwrap().is_some() {
                error!("Received config_vote for unknown transaciton, msg={:?}",
                       config_vote);
                return;
            }

            if let Some(vote) = view.config_votes().get(config_vote.from()).unwrap() {
                if vote.seed() != config_vote.seed() - 1 {
                    error!("Received config_vote with wrong seed, msg={:?}",
                           config_vote);
                    return;
                }
            }

            let msg = config_vote.clone();
            let _ = view.config_votes().put(msg.from(), config_vote.clone());

            let mut votes_count = 0;
            for pub_key in config.validators.clone() {
                if let Some(vote) = view.config_votes().get(&pub_key).unwrap() {
                    if !vote.revoke() {
                        votes_count += 1;
                    }
                }
            }

            if votes_count >= 2 / 3 * config.validators.len() {
                if let Some(config_propose) = view.config_proposes()
                    .get(config_vote.hash_propose())
                    .unwrap() {
                    let height_bytecode = config_propose.actual_from_height().into();
                    view.configs().put(&height_bytecode, config_propose.config().to_vec()).unwrap();
                    view.configs_heights().append(height_bytecode).unwrap();
                    // TODO: clear storages
                }
            }
        }
    }

    fn commit<'a, I: Iterator<Item = &'a Precommit>>(&self,
                                                     block_hash: Hash,
                                                     patch: &Patch,
                                                     precommits: I)
                                                     -> Result<(), Error> {
        let patch = {
            let view = self.view();
            view.merge(patch);

            for precommit in precommits {
                view.precommits(&block_hash).append(precommit.clone())?;
            }

            view.changes()
        };

        self.merge(&patch)
    }

    fn view(&self) -> Self::View {
        Self::View::from_fork(self.borrow().fork())
    }

    fn merge(&self, patch: &Patch) -> Result<(), Error> {
        self.deref().merge(patch)
    }
}
<|endoftext|>


<commit_before>use rustwlc::WlcOutput;
use petgraph::graph::NodeIndex;
use uuid::Uuid;
use super::super::{LayoutTree, TreeError, FocusError};
use ::layout::core::container::{Container, ContainerType, Layout, Handle};
use ::layout::core::borders::Borders;
use ::render::Renderable;
use ::debug_enabled;

// TODO This module needs to be updated like the other modules...
// Need to add some errors for this (such as when trying to move a non-container/view,
// or when trying to grab a workspace whos name already exists)
//
// Also the code is generally pretty crap, cause it's pretty old (mid-2016)

impl LayoutTree {
    /// Gets a workspace by name or creates it
    fn get_or_make_workspace(&mut self, name: &str) -> NodeIndex {
        let active_index = self.tree.follow_path_until(self.tree.root_ix(),
                                                      ContainerType::Output)
            .expect("get_or_make_wksp: Couldn't get output");
        let workspace_ix = self.tree.workspace_ix_by_name(name).unwrap_or_else(|| {
            let root_ix = self.init_workspace(name.to_string(), active_index);
            self.tree.parent_of(root_ix)
                .expect("Workspace was not properly initialized with a root container")
        });
        self.validate();
        workspace_ix
    }

    /// Initializes a workspace and gets the index of the root container
    pub fn init_workspace(&mut self, name: String, output_ix: NodeIndex)
                      -> NodeIndex {
        let geometry = self.tree.get(output_ix)
            .expect("init_workspace: invalid output").get_geometry()
            .expect("init_workspace: no geometry for output");
        let worksp = Container::new_workspace(name.to_string(), geometry);
        let output_handle = match self.tree[output_ix].get_handle() {
            Ok(Handle::Output(output)) => output,
            Err(err) => panic!("Could not get handle from output: {:#?}", err),
            _ => unreachable!()
        };

        trace!("Adding workspace {:?}", worksp);
        let worksp_ix = self.tree.add_child(output_ix, worksp, false);
        let borders = Borders::new(geometry, output_handle);
        let container = Container::new_container(geometry,
                                                 output_handle,
                                                 borders);
        let container_ix = self.tree.add_child(worksp_ix, container, false);
        self.tree.set_ancestor_paths_active(container_ix);
        self.validate();
        container_ix
    }

    /// Switch to the specified workspace
    pub fn switch_to_workspace(&mut self, name: &str) {
        let maybe_active_ix = self.active_container
            .or_else(|| {
                let new_active = self.tree.follow_path(self.tree.root_ix());
                match self.tree[new_active].get_type() {
                    ContainerType::View | ContainerType::Container => {
                        Some(new_active)
                    },
                    // else try and get the root container
                    _ => self.tree.descendant_of_type(new_active, ContainerType::Container).ok()
                }
            });
        if maybe_active_ix.is_none() {
            warn!("{:#?}", self);
            warn!("No active container, cannot switch");
            return;
        }
        let active_ix = maybe_active_ix.unwrap();
        // Get the old (current) workspace
        let old_worksp_ix: NodeIndex;
        if let Ok(index) = self.tree.ancestor_of_type(active_ix, ContainerType::Workspace) {
            old_worksp_ix = index;
            trace!("Switching to workspace {}", name);
        } else {
            match self.tree[active_ix].get_type() {
                ContainerType::Workspace => {
                    old_worksp_ix = active_ix;
                    trace!("Switching to workspace {}", name);
                },
                _ => {
                    warn!("Could not find old workspace, could not set invisible");
                    return;
                }
            }
        }
        // Get the new workspace, or create one if it doesn't work
        let mut workspace_ix = self.get_or_make_workspace(name);
        if old_worksp_ix == workspace_ix {
            return;
        }
        {
            // Update the border colors
            let container = &mut self.tree[active_ix];
            container.clear_border_color()
                .expect("Could not clear old active border color");
            container.draw_borders().expect("Could not draw borders");
        }
        let old_worksp_parent_ix = self.tree.parent_of(old_worksp_ix)
            .expect("Old workspace had no parent");
        let new_worksp_parent_ix = self.tree.parent_of(workspace_ix)
            .expect("New workspace had no parent");
        // Only set the old one to be invisible if new and old share output.
        if new_worksp_parent_ix == old_worksp_parent_ix {
            // Set the old one to invisible
            self.set_container_visibility(old_worksp_ix, false);
        } else {
            // Set all views on the target output to be invisible,
            // to clear the old workspace visibilty out.
            self.set_container_visibility(new_worksp_parent_ix, false);
        }
        // Set the new one to visible
        self.container_visibilty_wrapper(workspace_ix, true);
        // Focus on the new output
        match self.tree[new_worksp_parent_ix] {
            Container::Output { handle, .. } => {
                WlcOutput::focus(Some(handle))
            },
            _ => unreachable!()
        }
        // Delete the old workspace if it has no views on it
        self.active_container = None;
        if self.tree.descendant_of_type(old_worksp_ix, ContainerType::View).is_err() {
            let siblings = self.tree.children_of(old_worksp_parent_ix);
            // Only remove if it's **NOT** the only workspace on the output.
            // AND if the new workspace is on the same output.
            if siblings.len() > 1 && old_worksp_parent_ix == new_worksp_parent_ix {
                trace!("Removing workspace: {:?}", self.tree[old_worksp_ix].get_name()
                    .expect("Workspace had no name"));
                if let Err(err) = self.remove_workspace(old_worksp_ix) {
                    warn!("Tried to remove empty workspace {:#?}, error: {:?}",
                        old_worksp_ix, err);
                    info!("{:#?}", self);
                    panic!("Could not remove old workspace");
                }
            }
        }
        workspace_ix = self.tree.workspace_ix_by_name(name)
            .expect("Workspace we just made was deleted!");
        let active_ix = self.tree.follow_path(workspace_ix);
        match self.tree[active_ix].get_type() {
            ContainerType::View  => {
                match self.tree[active_ix] {
                    Container::View { id, ..} => {
                        self.focus_on(id).unwrap_or_else(|_| {
                            warn!("Could not focus on {:?}", id);
                        });
                    },
                    _ => unreachable!()
                }
                // TODO Propogate this when this is refactored
                match self.set_active_node(active_ix) {
                    Err(TreeError::Focus(
                        FocusError::BlockedByFullscreen(_, focus_id))) => {
                        // If blocked, didn't get a chance to set it
                        self.active_container = self.tree.lookup_id(focus_id);
                        Ok(())
                    },
                    other => other
                }.expect("Could not set new active node");
                self.tree.set_ancestor_paths_active(active_ix);
                self.layout(workspace_ix);
                self.validate();
                self.validate_path();
                return;
            },
            _ => {
                self.active_container = self.tree
                    .descendant_of_type(active_ix, ContainerType::View)
                    .or_else(|_| self.tree.descendant_of_type(active_ix,
                                                              ContainerType::Container)).ok();
                match self.tree[self.active_container.expect("Workspace had NO children!")] {
                    Container::View { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    },
                    Container::Container { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    }
                    _ => unreachable!()
                };
            }
        }
        trace!("Focusing on next container");
        self.focus_on_next_container(workspace_ix);
        self.layout(workspace_ix);
        self.validate();
        self.validate_path();
    }

    /// Moves the active container to a new workspace.
    pub fn send_active_to_workspace(&mut self, name: &str) {
        if let Some(active_ix) = self.active_container {
            let id = self.tree[active_ix].get_id();
            self.send_to_workspace(id, name);
        }
    }
    /// Moves a container to a new workspace
    pub fn send_to_workspace(&mut self, id: Uuid, name: &str) {
        let node_ix = self.tree.lookup_id(id);
        // Ensure focus
        // TODO Need to not make it default, but need to add tests to make
        // sure that doesn't cause a regression.
        if let Some(active_ix) = node_ix.or(self.active_container) {
            let curr_work_ix = self.active_ix_of(ContainerType::Workspace)
                .expect("send_active: Not currently in a workspace!");
            if active_ix == self.tree.children_of(curr_work_ix)[0] {
                warn!("Tried to move the root container of a workspace, aborting move");
                return;
            }
            let next_work_ix = self.get_or_make_workspace(name);

            // Check if the workspaces are the same
            if next_work_ix == curr_work_ix {
                trace!("Attempted to move a view to the same workspace {}!", name);
                return;
            }
            self.set_container_visibility(curr_work_ix, false);
            let new_output_ix = self.tree.parent_of(next_work_ix)
                .expect("Target workspace had no parent");
            match self.tree[new_output_ix] {
                Container::Output { handle: output_handle, .. } => {
                    fn set_output_recurse(this: &mut LayoutTree,
                                          node_ix: NodeIndex,
                                          output_handle: WlcOutput) {
                        match this.tree[node_ix].get_type() {
                            ContainerType::View => {
                                this.tree[node_ix].update_border_output(output_handle)
                                    .expect("Could not update border output for view");
                            },
                            ContainerType::Container => {
                                this.tree[node_ix].update_border_output(output_handle)
                                    .expect("Could not update border output for view");
                                for child_ix in this.tree.children_of(node_ix) {
                                    set_output_recurse(this, child_ix, output_handle)
                                }
                            },
                            _ => unreachable!()
                        }
                    }
                    set_output_recurse(self, active_ix, output_handle);
                },
                _ => unreachable!()
            }

            // Save the parent of this view for focusing
            let maybe_active_parent = self.tree.parent_of(active_ix);

            // Get the root container of the next workspace
            let next_work_children = self.tree.children_of(next_work_ix);
            if cfg!(debug_assertions) || !debug_enabled() {
                assert!(next_work_children.len() == 1,
                        "Next workspace has multiple roots!");
            }
            let next_work_root_ix = next_work_children[0];

            // Move the container
            info!("Moving container {:?} to workspace {}",
                self.get_active_container(), name);
            self.tree.move_node(active_ix, next_work_root_ix);

            let cur_output_ix = self.tree.parent_of(curr_work_ix)
                .expect("Couldn't get parent of current work index");
            let next_is_vis = self.tree.on_path(next_work_root_ix);
            // If different outputs, show it on the new output if workspace is vis.
            if new_output_ix != cur_output_ix && next_is_vis {
                self.container_visibilty_wrapper(new_output_ix, true);
            }

            // If it's a fullscreen app, then update the fullscreen lists
            self.transfer_fullscreen(curr_work_ix, next_work_ix, id);

            // Update the active container
            if let Ok(parent_ix) = maybe_active_parent {
                self.tree.set_ancestor_paths_active(parent_ix);
                let ctype = self.tree.node_type(parent_ix).unwrap_or(ContainerType::Root);
                if ctype == ContainerType::Container {
                    self.focus_on_next_container(parent_ix);
                } else {
                    trace!("Send to container invalidated a NodeIndex: {:?} to {:?}",
                    parent_ix, ctype);
                }
                if self.tree.can_remove_empty_parent(parent_ix) {
                    if let Err(err) = self.remove_view_or_container(parent_ix) {
                        error!("{:#?}\nCould not remove {:#?} from tree {:#?}", err, parent_ix, self);
                        panic!("Could not remove empty parent!");
                    }
                }
            }
            else {
                self.focus_on_next_container(curr_work_ix);
            }
            self.container_visibilty_wrapper(curr_work_ix, true);
            if !self.tree[active_ix].floating() {
                self.normalize_container(active_ix).ok();
            }
        }
        let root_ix = self.tree.root_ix();
        self.layout(root_ix);
        self.validate();
        self.validate_path();
    }

    /// Transfers a fullscreen app from this workspace to another.
    fn transfer_fullscreen(&mut self, cur_work_ix: NodeIndex, next_work_ix: NodeIndex,
                           fullscreen_id: Uuid) {
        if let Some(fullscreen_ids) = self.tree[cur_work_ix].fullscreen_c() {
            if !fullscreen_ids.iter().any(|id| *id == fullscreen_id) {
                return;
            }
        } else {
            return;
        }
        self.tree[cur_work_ix].update_fullscreen_c(fullscreen_id, false)
            .expect("cur_work_ix was not a workspace");
        self.tree[next_work_ix].update_fullscreen_c(fullscreen_id, true)
            .expect("next_work_ix was not a workspace");
    }

    /// Wrapper around `set_container_visibility`, so that tabbed/stacked
    /// is handled correctly (i.e, it's visibilty checks are skipped).
    fn container_visibilty_wrapper(&mut self, node_ix: NodeIndex, val: bool) {
        let mut set = false;
        match self.tree[node_ix] {
            Container::Container { layout, .. } => {
                match layout {
                    Layout::Tabbed | Layout::Stacked => {
                        if val {
                            set = true;
                        }
                    },
                    _ => {}
                }
            },
            _ => {}
        }
        if !set {
            self.tree[node_ix].set_visibility(val);
            for child in self.tree.children_of(node_ix) {
                self.container_visibilty_wrapper(child, val)
            }
        } else {
            self.tree.next_active_node(node_ix)
                .map(|node| self.container_visibilty_wrapper(node, val));
        }
    }

    /// Gets the current workspace we are focused on
    ///
    /// If a workspace is not found, this is considered a hard error and
    /// it will panic.
    #[allow(dead_code)]
    pub fn current_workspace(&self) -> Result<&str, TreeError> {
        let active_ix = self.active_container
            .ok_or(TreeError::NoActiveContainer)?;
        let workspace_ix = self.tree.ancestor_of_type(active_ix,
                                                      ContainerType::Workspace)?;
        Ok(self.tree[workspace_ix].get_name()
           .expect("workspace_ix didn't point to a workspace!"))
    }
}

#[cfg(test)]
mod tests {
    use ::layout::core::tree::tests::basic_tree;

    #[test]
    pub fn switch_empty_workspaces() {
        let mut tree = basic_tree();
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("2");
    }
}
<commit_msg>Revert "Only show on new output if workspace is vis"<commit_after>use rustwlc::WlcOutput;
use petgraph::graph::NodeIndex;
use uuid::Uuid;
use super::super::{LayoutTree, TreeError, FocusError};
use ::layout::core::container::{Container, ContainerType, Layout, Handle};
use ::layout::core::borders::Borders;
use ::render::Renderable;
use ::debug_enabled;

// TODO This module needs to be updated like the other modules...
// Need to add some errors for this (such as when trying to move a non-container/view,
// or when trying to grab a workspace whos name already exists)
//
// Also the code is generally pretty crap, cause it's pretty old (mid-2016)

impl LayoutTree {
    /// Gets a workspace by name or creates it
    fn get_or_make_workspace(&mut self, name: &str) -> NodeIndex {
        let active_index = self.tree.follow_path_until(self.tree.root_ix(),
                                                      ContainerType::Output)
            .expect("get_or_make_wksp: Couldn't get output");
        let workspace_ix = self.tree.workspace_ix_by_name(name).unwrap_or_else(|| {
            let root_ix = self.init_workspace(name.to_string(), active_index);
            self.tree.parent_of(root_ix)
                .expect("Workspace was not properly initialized with a root container")
        });
        self.validate();
        workspace_ix
    }

    /// Initializes a workspace and gets the index of the root container
    pub fn init_workspace(&mut self, name: String, output_ix: NodeIndex)
                      -> NodeIndex {
        let geometry = self.tree.get(output_ix)
            .expect("init_workspace: invalid output").get_geometry()
            .expect("init_workspace: no geometry for output");
        let worksp = Container::new_workspace(name.to_string(), geometry);
        let output_handle = match self.tree[output_ix].get_handle() {
            Ok(Handle::Output(output)) => output,
            Err(err) => panic!("Could not get handle from output: {:#?}", err),
            _ => unreachable!()
        };

        trace!("Adding workspace {:?}", worksp);
        let worksp_ix = self.tree.add_child(output_ix, worksp, false);
        let borders = Borders::new(geometry, output_handle);
        let container = Container::new_container(geometry,
                                                 output_handle,
                                                 borders);
        let container_ix = self.tree.add_child(worksp_ix, container, false);
        self.tree.set_ancestor_paths_active(container_ix);
        self.validate();
        container_ix
    }

    /// Switch to the specified workspace
    pub fn switch_to_workspace(&mut self, name: &str) {
        let maybe_active_ix = self.active_container
            .or_else(|| {
                let new_active = self.tree.follow_path(self.tree.root_ix());
                match self.tree[new_active].get_type() {
                    ContainerType::View | ContainerType::Container => {
                        Some(new_active)
                    },
                    // else try and get the root container
                    _ => self.tree.descendant_of_type(new_active, ContainerType::Container).ok()
                }
            });
        if maybe_active_ix.is_none() {
            warn!("{:#?}", self);
            warn!("No active container, cannot switch");
            return;
        }
        let active_ix = maybe_active_ix.unwrap();
        // Get the old (current) workspace
        let old_worksp_ix: NodeIndex;
        if let Ok(index) = self.tree.ancestor_of_type(active_ix, ContainerType::Workspace) {
            old_worksp_ix = index;
            trace!("Switching to workspace {}", name);
        } else {
            match self.tree[active_ix].get_type() {
                ContainerType::Workspace => {
                    old_worksp_ix = active_ix;
                    trace!("Switching to workspace {}", name);
                },
                _ => {
                    warn!("Could not find old workspace, could not set invisible");
                    return;
                }
            }
        }
        // Get the new workspace, or create one if it doesn't work
        let mut workspace_ix = self.get_or_make_workspace(name);
        if old_worksp_ix == workspace_ix {
            return;
        }
        {
            // Update the border colors
            let container = &mut self.tree[active_ix];
            container.clear_border_color()
                .expect("Could not clear old active border color");
            container.draw_borders().expect("Could not draw borders");
        }
        let old_worksp_parent_ix = self.tree.parent_of(old_worksp_ix)
            .expect("Old workspace had no parent");
        let new_worksp_parent_ix = self.tree.parent_of(workspace_ix)
            .expect("New workspace had no parent");
        // Only set the old one to be invisible if new and old share output.
        if new_worksp_parent_ix == old_worksp_parent_ix {
            // Set the old one to invisible
            self.set_container_visibility(old_worksp_ix, false);
        } else {
            // Set all views on the target output to be invisible,
            // to clear the old workspace visibilty out.
            self.set_container_visibility(new_worksp_parent_ix, false);
        }
        // Set the new one to visible
        self.container_visibilty_wrapper(workspace_ix, true);
        // Focus on the new output
        match self.tree[new_worksp_parent_ix] {
            Container::Output { handle, .. } => {
                WlcOutput::focus(Some(handle))
            },
            _ => unreachable!()
        }
        // Delete the old workspace if it has no views on it
        self.active_container = None;
        if self.tree.descendant_of_type(old_worksp_ix, ContainerType::View).is_err() {
            let siblings = self.tree.children_of(old_worksp_parent_ix);
            // Only remove if it's **NOT** the only workspace on the output.
            // AND if the new workspace is on the same output.
            if siblings.len() > 1 && old_worksp_parent_ix == new_worksp_parent_ix {
                trace!("Removing workspace: {:?}", self.tree[old_worksp_ix].get_name()
                    .expect("Workspace had no name"));
                if let Err(err) = self.remove_workspace(old_worksp_ix) {
                    warn!("Tried to remove empty workspace {:#?}, error: {:?}",
                        old_worksp_ix, err);
                    info!("{:#?}", self);
                    panic!("Could not remove old workspace");
                }
            }
        }
        workspace_ix = self.tree.workspace_ix_by_name(name)
            .expect("Workspace we just made was deleted!");
        let active_ix = self.tree.follow_path(workspace_ix);
        match self.tree[active_ix].get_type() {
            ContainerType::View  => {
                match self.tree[active_ix] {
                    Container::View { id, ..} => {
                        self.focus_on(id).unwrap_or_else(|_| {
                            warn!("Could not focus on {:?}", id);
                        });
                    },
                    _ => unreachable!()
                }
                // TODO Propogate this when this is refactored
                match self.set_active_node(active_ix) {
                    Err(TreeError::Focus(
                        FocusError::BlockedByFullscreen(_, focus_id))) => {
                        // If blocked, didn't get a chance to set it
                        self.active_container = self.tree.lookup_id(focus_id);
                        Ok(())
                    },
                    other => other
                }.expect("Could not set new active node");
                self.tree.set_ancestor_paths_active(active_ix);
                self.layout(workspace_ix);
                self.validate();
                self.validate_path();
                return;
            },
            _ => {
                self.active_container = self.tree
                    .descendant_of_type(active_ix, ContainerType::View)
                    .or_else(|_| self.tree.descendant_of_type(active_ix,
                                                              ContainerType::Container)).ok();
                match self.tree[self.active_container.expect("Workspace had NO children!")] {
                    Container::View { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    },
                    Container::Container { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    }
                    _ => unreachable!()
                };
            }
        }
        trace!("Focusing on next container");
        self.focus_on_next_container(workspace_ix);
        self.layout(workspace_ix);
        self.validate();
        self.validate_path();
    }

    /// Moves the active container to a new workspace.
    pub fn send_active_to_workspace(&mut self, name: &str) {
        if let Some(active_ix) = self.active_container {
            let id = self.tree[active_ix].get_id();
            self.send_to_workspace(id, name);
        }
    }
    /// Moves a container to a new workspace
    pub fn send_to_workspace(&mut self, id: Uuid, name: &str) {
        let node_ix = self.tree.lookup_id(id);
        // Ensure focus
        // TODO Need to not make it default, but need to add tests to make
        // sure that doesn't cause a regression.
        if let Some(active_ix) = node_ix.or(self.active_container) {
            let curr_work_ix = self.active_ix_of(ContainerType::Workspace)
                .expect("send_active: Not currently in a workspace!");
            if active_ix == self.tree.children_of(curr_work_ix)[0] {
                warn!("Tried to move the root container of a workspace, aborting move");
                return;
            }
            let next_work_ix = self.get_or_make_workspace(name);

            // Check if the workspaces are the same
            if next_work_ix == curr_work_ix {
                trace!("Attempted to move a view to the same workspace {}!", name);
                return;
            }
            self.set_container_visibility(curr_work_ix, false);
            let new_output_ix = self.tree.parent_of(next_work_ix)
                .expect("Target workspace had no parent");
            match self.tree[new_output_ix] {
                Container::Output { handle: output_handle, .. } => {
                    fn set_output_recurse(this: &mut LayoutTree,
                                          node_ix: NodeIndex,
                                          output_handle: WlcOutput) {
                        match this.tree[node_ix].get_type() {
                            ContainerType::View => {
                                this.tree[node_ix].update_border_output(output_handle)
                                    .expect("Could not update border output for view");
                            },
                            ContainerType::Container => {
                                this.tree[node_ix].update_border_output(output_handle)
                                    .expect("Could not update border output for view");
                                for child_ix in this.tree.children_of(node_ix) {
                                    set_output_recurse(this, child_ix, output_handle)
                                }
                            },
                            _ => unreachable!()
                        }
                    }
                    set_output_recurse(self, active_ix, output_handle);
                },
                _ => unreachable!()
            }

            // Save the parent of this view for focusing
            let maybe_active_parent = self.tree.parent_of(active_ix);

            // Get the root container of the next workspace
            let next_work_children = self.tree.children_of(next_work_ix);
            if cfg!(debug_assertions) || !debug_enabled() {
                assert!(next_work_children.len() == 1,
                        "Next workspace has multiple roots!");
            }
            let next_work_root_ix = next_work_children[0];

            // Move the container
            info!("Moving container {:?} to workspace {}",
                self.get_active_container(), name);
            self.tree.move_node(active_ix, next_work_root_ix);

            // If different outputs, show it on the new output.
            let cur_output_ix = self.tree.parent_of(curr_work_ix)
                .expect("Couldn't get parent of current work index");
            if new_output_ix != cur_output_ix {
                self.container_visibilty_wrapper(new_output_ix, true);
            }

            // If it's a fullscreen app, then update the fullscreen lists
            self.transfer_fullscreen(curr_work_ix, next_work_ix, id);

            // Update the active container
            if let Ok(parent_ix) = maybe_active_parent {
                self.tree.set_ancestor_paths_active(parent_ix);
                let ctype = self.tree.node_type(parent_ix).unwrap_or(ContainerType::Root);
                if ctype == ContainerType::Container {
                    self.focus_on_next_container(parent_ix);
                } else {
                    trace!("Send to container invalidated a NodeIndex: {:?} to {:?}",
                    parent_ix, ctype);
                }
                if self.tree.can_remove_empty_parent(parent_ix) {
                    if let Err(err) = self.remove_view_or_container(parent_ix) {
                        error!("{:#?}\nCould not remove {:#?} from tree {:#?}", err, parent_ix, self);
                        panic!("Could not remove empty parent!");
                    }
                }
            }
            else {
                self.focus_on_next_container(curr_work_ix);
            }
            self.container_visibilty_wrapper(curr_work_ix, true);
            if !self.tree[active_ix].floating() {
                self.normalize_container(active_ix).ok();
            }
        }
        let root_ix = self.tree.root_ix();
        self.layout(root_ix);
        self.validate();
        self.validate_path();
    }

    /// Transfers a fullscreen app from this workspace to another.
    fn transfer_fullscreen(&mut self, cur_work_ix: NodeIndex, next_work_ix: NodeIndex,
                           fullscreen_id: Uuid) {
        if let Some(fullscreen_ids) = self.tree[cur_work_ix].fullscreen_c() {
            if !fullscreen_ids.iter().any(|id| *id == fullscreen_id) {
                return;
            }
        } else {
            return;
        }
        self.tree[cur_work_ix].update_fullscreen_c(fullscreen_id, false)
            .expect("cur_work_ix was not a workspace");
        self.tree[next_work_ix].update_fullscreen_c(fullscreen_id, true)
            .expect("next_work_ix was not a workspace");
    }

    /// Wrapper around `set_container_visibility`, so that tabbed/stacked
    /// is handled correctly (i.e, it's visibilty checks are skipped).
    fn container_visibilty_wrapper(&mut self, node_ix: NodeIndex, val: bool) {
        let mut set = false;
        match self.tree[node_ix] {
            Container::Container { layout, .. } => {
                match layout {
                    Layout::Tabbed | Layout::Stacked => {
                        if val {
                            set = true;
                        }
                    },
                    _ => {}
                }
            },
            _ => {}
        }
        if !set {
            self.tree[node_ix].set_visibility(val);
            for child in self.tree.children_of(node_ix) {
                self.container_visibilty_wrapper(child, val)
            }
        } else {
            self.tree.next_active_node(node_ix)
                .map(|node| self.container_visibilty_wrapper(node, val));
        }
    }

    /// Gets the current workspace we are focused on
    ///
    /// If a workspace is not found, this is considered a hard error and
    /// it will panic.
    #[allow(dead_code)]
    pub fn current_workspace(&self) -> Result<&str, TreeError> {
        let active_ix = self.active_container
            .ok_or(TreeError::NoActiveContainer)?;
        let workspace_ix = self.tree.ancestor_of_type(active_ix,
                                                      ContainerType::Workspace)?;
        Ok(self.tree[workspace_ix].get_name()
           .expect("workspace_ix didn't point to a workspace!"))
    }
}

#[cfg(test)]
mod tests {
    use ::layout::core::tree::tests::basic_tree;

    #[test]
    pub fn switch_empty_workspaces() {
        let mut tree = basic_tree();
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("2");
    }
}
<|endoftext|>


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

// The outlines relation `T: 'a` or `'a: 'b`.

use middle::infer::InferCtxt;
use middle::ty::{self, RegionEscape, Ty};

#[derive(Debug)]
pub enum Component<'tcx> {
    Region(ty::Region),
    Param(ty::ParamTy),
    UnresolvedInferenceVariable(ty::InferTy),

    // Projections like `T::Foo` are tricky because a constraint like
    // `T::Foo: 'a` can be satisfied in so many ways. There may be a
    // where-clause that says `T::Foo: 'a`, or the defining trait may
    // include a bound like `type Foo: 'static`, or -- in the most
    // conservative way -- we can prove that `T: 'a` (more generally,
    // that all components in the projection outlive `'a`). This code
    // is not in a position to judge which is the best technique, so
    // we just product the projection as a component and leave it to
    // the consumer to decide (but see `EscapingProjection` below).
    Projection(ty::ProjectionTy<'tcx>),

    // In the case where a projection has escaping regions -- meaning
    // regions bound within the type itself -- we always use
    // the most conservative rule, which requires that all components
    // outlive the bound. So for example if we had a type like this:
    //
    //     for<'a> Trait1<  <T as Trait2<'a,'b>>::Foo  >
    //                      ~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // then the inner projection (underlined) has an escaping region
    // `'a`. We consider that outer trait `'c` to meet a bound if `'b`
    // outlives `'b: 'c`, and we don't consider whether the trait
    // declares that `Foo: 'static` etc. Therefore, we just return the
    // free components of such a projection (in this case, `'b`).
    //
    // However, in the future, we may want to get smarter, and
    // actually return a "higher-ranked projection" here. Therefore,
    // we mark that these components are part of an escaping
    // projection, so that implied bounds code can avoid relying on
    // them. This gives us room to improve the regionck reasoning in
    // the future without breaking backwards compat.
    EscapingProjection(Vec<Component<'tcx>>),

    RFC1214(Vec<Component<'tcx>>),
}

/// Returns all the things that must outlive `'a` for the condition
/// `ty0: 'a` to hold.
pub fn components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                           ty0: Ty<'tcx>)
                           -> Vec<Component<'tcx>> {
    let mut components = vec![];
    compute_components(infcx, ty0, &mut components);
    debug!("outlives({:?}) = {:?}", ty0, components);
    components
}

fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                               ty0: Ty<'tcx>,
                               out: &mut Vec<Component<'tcx>>) {
    // Descend through the types, looking for the various "base"
    // components and collecting them into `out`. This is not written
    // with `collect()` because of the need to sometimes skip subtrees
    // in the `subtys` iterator (e.g., when encountering a
    // projection).
    let mut subtys = ty0.walk();
    while let Some(ty) = subtys.next() {
        match ty.sty {
            ty::TyClosure(_, ref substs) => {
                // FIXME(#27086). We do not accumulate from substs, since they
                // don't represent reachable data. This means that, in
                // practice, some of the lifetime parameters might not
                // be in scope when the body runs, so long as there is
                // no reachable data with that lifetime. For better or
                // worse, this is consistent with fn types, however,
                // which can also encapsulate data in this fashion
                // (though it's somewhat harder, and typically
                // requires virtual dispatch).
                //
                // Note that changing this (in a naive way, at least)
                // causes regressions for what appears to be perfectly
                // reasonable code like this:
                //
                // ```
                // fn foo<'a>(p: &Data<'a>) {
                //    bar(|q: &mut Parser| q.read_addr())
                // }
                // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
                // }
                // ```
                //
                // Note that `p` (and `'a`) are not used in the
                // closure at all, but to meet the requirement that
                // the closure type `C: 'static` (so it can be coerced
                // to the object type), we get the requirement that
                // `'a: 'static` since `'a` appears in the closure
                // type `C`.
                //
                // A smarter fix might "prune" unused `func_substs` --
                // this would avoid breaking simple examples like
                // this, but would still break others (which might
                // indeed be invalid, depending on your POV). Pruning
                // would be a subtle process, since we have to see
                // what func/type parameters are used and unused,
                // taking into consideration UFCS and so forth.

                for &upvar_ty in &substs.upvar_tys {
                    compute_components(infcx, upvar_ty, out);
                }
                subtys.skip_current_subtree();
            }
            ty::TyBareFn(..) | ty::TyTrait(..) => {
                subtys.skip_current_subtree();
                let temp = capture_components(infcx, ty);
                out.push(Component::RFC1214(temp));
            }
            ty::TyParam(p) => {
                out.push(Component::Param(p));
                subtys.skip_current_subtree();
            }
            ty::TyProjection(ref data) => {
                // For projections, we prefer to generate an
                // obligation like `<P0 as Trait<P1...Pn>>::Foo: 'a`,
                // because this gives the regionck more ways to prove
                // that it holds. However, regionck is not (at least
                // currently) prepared to deal with higher-ranked
                // regions that may appear in the
                // trait-ref. Therefore, if we see any higher-ranke
                // regions, we simply fallback to the most restrictive
                // rule, which requires that `Pi: 'a` for all `i`.

                if !data.has_escaping_regions() {
                    // best case: no escaping regions, so push the
                    // projection and skip the subtree (thus
                    // generating no constraints for Pi).
                    out.push(Component::Projection(*data));
                } else {
                    // fallback case: continue walking through and
                    // constrain Pi.
                    let temp = capture_components(infcx, ty);
                    out.push(Component::EscapingProjection(temp));
                }
                subtys.skip_current_subtree();
            }
            ty::TyInfer(_) => {
                let ty = infcx.resolve_type_vars_if_possible(&ty);
                if let ty::TyInfer(infer_ty) = ty.sty {
                    out.push(Component::UnresolvedInferenceVariable(infer_ty));
                } else {
                    compute_components(infcx, ty, out);
                }
            }
            _ => {
                // for all other types, just constrain the regions and
                // keep walking to find any other types.
                push_region_constraints(out, ty.regions());
            }
        }
    }
}

fn capture_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                               ty: Ty<'tcx>)
                               -> Vec<Component<'tcx>> {
    let mut temp = vec![];
    push_region_constraints(&mut temp, ty.regions());
    for subty in ty.walk_shallow() {
        compute_components(infcx, subty, &mut temp);
    }
    temp
}

fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region>) {
    for r in regions {
        if !r.is_bound() {
            out.push(Component::Region(r));
        }
    }
}

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

// The outlines relation `T: 'a` or `'a: 'b`.

use middle::infer::InferCtxt;
use middle::ty::{self, RegionEscape, Ty};

#[derive(Debug)]
pub enum Component<'tcx> {
    Region(ty::Region),
    Param(ty::ParamTy),
    UnresolvedInferenceVariable(ty::InferTy),

    // Projections like `T::Foo` are tricky because a constraint like
    // `T::Foo: 'a` can be satisfied in so many ways. There may be a
    // where-clause that says `T::Foo: 'a`, or the defining trait may
    // include a bound like `type Foo: 'static`, or -- in the most
    // conservative way -- we can prove that `T: 'a` (more generally,
    // that all components in the projection outlive `'a`). This code
    // is not in a position to judge which is the best technique, so
    // we just product the projection as a component and leave it to
    // the consumer to decide (but see `EscapingProjection` below).
    Projection(ty::ProjectionTy<'tcx>),

    // In the case where a projection has escaping regions -- meaning
    // regions bound within the type itself -- we always use
    // the most conservative rule, which requires that all components
    // outlive the bound. So for example if we had a type like this:
    //
    //     for<'a> Trait1<  <T as Trait2<'a,'b>>::Foo  >
    //                      ~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // then the inner projection (underlined) has an escaping region
    // `'a`. We consider that outer trait `'c` to meet a bound if `'b`
    // outlives `'b: 'c`, and we don't consider whether the trait
    // declares that `Foo: 'static` etc. Therefore, we just return the
    // free components of such a projection (in this case, `'b`).
    //
    // However, in the future, we may want to get smarter, and
    // actually return a "higher-ranked projection" here. Therefore,
    // we mark that these components are part of an escaping
    // projection, so that implied bounds code can avoid relying on
    // them. This gives us room to improve the regionck reasoning in
    // the future without breaking backwards compat.
    EscapingProjection(Vec<Component<'tcx>>),

    RFC1214(Vec<Component<'tcx>>),
}

/// Returns all the things that must outlive `'a` for the condition
/// `ty0: 'a` to hold.
pub fn components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                           ty0: Ty<'tcx>)
                           -> Vec<Component<'tcx>> {
    let mut components = vec![];
    compute_components(infcx, ty0, &mut components);
    debug!("outlives({:?}) = {:?}", ty0, components);
    components
}

fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                               ty0: Ty<'tcx>,
                               out: &mut Vec<Component<'tcx>>) {
    // Descend through the types, looking for the various "base"
    // components and collecting them into `out`. This is not written
    // with `collect()` because of the need to sometimes skip subtrees
    // in the `subtys` iterator (e.g., when encountering a
    // projection).
    let mut subtys = ty0.walk();
    while let Some(ty) = subtys.next() {
        match ty.sty {
            ty::TyClosure(_, ref substs) => {
                // FIXME(#27086). We do not accumulate from substs, since they
                // don't represent reachable data. This means that, in
                // practice, some of the lifetime parameters might not
                // be in scope when the body runs, so long as there is
                // no reachable data with that lifetime. For better or
                // worse, this is consistent with fn types, however,
                // which can also encapsulate data in this fashion
                // (though it's somewhat harder, and typically
                // requires virtual dispatch).
                //
                // Note that changing this (in a naive way, at least)
                // causes regressions for what appears to be perfectly
                // reasonable code like this:
                //
                // ```
                // fn foo<'a>(p: &Data<'a>) {
                //    bar(|q: &mut Parser| q.read_addr())
                // }
                // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
                // }
                // ```
                //
                // Note that `p` (and `'a`) are not used in the
                // closure at all, but to meet the requirement that
                // the closure type `C: 'static` (so it can be coerced
                // to the object type), we get the requirement that
                // `'a: 'static` since `'a` appears in the closure
                // type `C`.
                //
                // A smarter fix might "prune" unused `func_substs` --
                // this would avoid breaking simple examples like
                // this, but would still break others (which might
                // indeed be invalid, depending on your POV). Pruning
                // would be a subtle process, since we have to see
                // what func/type parameters are used and unused,
                // taking into consideration UFCS and so forth.

                for &upvar_ty in &substs.upvar_tys {
                    compute_components(infcx, upvar_ty, out);
                }
                subtys.skip_current_subtree();
            }
            ty::TyBareFn(..) | ty::TyTrait(..) => {
                subtys.skip_current_subtree();
                let subcomponents = capture_components(infcx, ty);
                out.push(Component::RFC1214(subcomponents));
            }
            ty::TyParam(p) => {
                out.push(Component::Param(p));
                subtys.skip_current_subtree();
            }
            ty::TyProjection(ref data) => {
                // For projections, we prefer to generate an
                // obligation like `<P0 as Trait<P1...Pn>>::Foo: 'a`,
                // because this gives the regionck more ways to prove
                // that it holds. However, regionck is not (at least
                // currently) prepared to deal with higher-ranked
                // regions that may appear in the
                // trait-ref. Therefore, if we see any higher-ranke
                // regions, we simply fallback to the most restrictive
                // rule, which requires that `Pi: 'a` for all `i`.

                if !data.has_escaping_regions() {
                    // best case: no escaping regions, so push the
                    // projection and skip the subtree (thus
                    // generating no constraints for Pi).
                    out.push(Component::Projection(*data));
                } else {
                    // fallback case: continue walking through and
                    // constrain Pi.
                    let subcomponents = capture_components(infcx, ty);
                    out.push(Component::EscapingProjection(subcomponents));
                }
                subtys.skip_current_subtree();
            }
            ty::TyInfer(_) => {
                let ty = infcx.resolve_type_vars_if_possible(&ty);
                if let ty::TyInfer(infer_ty) = ty.sty {
                    out.push(Component::UnresolvedInferenceVariable(infer_ty));
                } else {
                    compute_components(infcx, ty, out);
                }
            }
            _ => {
                // for all other types, just constrain the regions and
                // keep walking to find any other types.
                push_region_constraints(out, ty.regions());
            }
        }
    }
}

fn capture_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                               ty: Ty<'tcx>)
                               -> Vec<Component<'tcx>> {
    let mut temp = vec![];
    push_region_constraints(&mut temp, ty.regions());
    for subty in ty.walk_shallow() {
        compute_components(infcx, subty, &mut temp);
    }
    temp
}

fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region>) {
    for r in regions {
        if !r.is_bound() {
            out.push(Component::Region(r));
        }
    }
}

<|endoftext|>


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

use cell::UnsafeCell;
use intrinsics::{atomic_cxchg, atomic_xadd, atomic_xchg};
use ptr;
use time::Duration;

use sys::mutex::{mutex_lock, mutex_unlock, Mutex};
use sys::syscall::{futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE};

pub struct Condvar {
    lock: UnsafeCell<*mut i32>,
    seq: UnsafeCell<i32>
}

impl Condvar {
    pub const fn new() -> Condvar {
        Condvar {
            lock: UnsafeCell::new(ptr::null_mut()),
            seq: UnsafeCell::new(0)
        }
    }

    #[inline]
    pub unsafe fn init(&self) {
        *self.lock.get() = ptr::null_mut();
        *self.seq.get() = 0;
    }

    #[inline]
    pub fn notify_one(&self) {
        unsafe {
            let seq = self.seq.get();

            atomic_xadd(seq, 1);

            let _ = futex(seq, FUTEX_WAKE, 1, 0, ptr::null_mut());
        }
    }

    #[inline]
    pub fn notify_all(&self) {
        unsafe {
            let lock = self.lock.get();
            let seq = self.seq.get();

            if *lock == ptr::null_mut() {
                return;
            }

            atomic_xadd(seq, 1);

            let _ = futex(seq, FUTEX_REQUEUE, 1, ::usize::MAX, *lock);
        }
    }

    #[inline]
    pub fn wait(&self, mutex: &Mutex) {
        unsafe {
            let lock = self.lock.get();
            let seq = self.seq.get();

            if *lock != mutex.lock.get() {
                if *lock != ptr::null_mut() {
                    panic!("Condvar used with more than one Mutex");
                }

                atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize);
            }

            mutex_unlock(*lock);

            let _ = futex(seq, FUTEX_WAIT, *seq, 0, ptr::null_mut());

            while atomic_xchg(*lock, 2) != 0 {
                let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut());
            }

            mutex_lock(*lock);
        }
    }

    #[inline]
    pub fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
        ::sys_common::util::dumb_print(format_args!("condvar wait_timeout\n"));
        unimplemented!();
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        *self.lock.get() = ptr::null_mut();
        *self.seq.get() = 0;
    }
}

unsafe impl Send for Condvar {}

unsafe impl Sync for Condvar {}
<commit_msg>Redox: Fix Condvar.wait(); do not lock mutex twice<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use cell::UnsafeCell;
use intrinsics::{atomic_cxchg, atomic_xadd, atomic_xchg};
use ptr;
use time::Duration;

use sys::mutex::{mutex_unlock, Mutex};
use sys::syscall::{futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE};

pub struct Condvar {
    lock: UnsafeCell<*mut i32>,
    seq: UnsafeCell<i32>
}

impl Condvar {
    pub const fn new() -> Condvar {
        Condvar {
            lock: UnsafeCell::new(ptr::null_mut()),
            seq: UnsafeCell::new(0)
        }
    }

    #[inline]
    pub unsafe fn init(&self) {
        *self.lock.get() = ptr::null_mut();
        *self.seq.get() = 0;
    }

    #[inline]
    pub fn notify_one(&self) {
        unsafe {
            let seq = self.seq.get();

            atomic_xadd(seq, 1);

            let _ = futex(seq, FUTEX_WAKE, 1, 0, ptr::null_mut());
        }
    }

    #[inline]
    pub fn notify_all(&self) {
        unsafe {
            let lock = self.lock.get();
            let seq = self.seq.get();

            if *lock == ptr::null_mut() {
                return;
            }

            atomic_xadd(seq, 1);

            let _ = futex(seq, FUTEX_REQUEUE, 1, ::usize::MAX, *lock);
        }
    }

    #[inline]
    pub fn wait(&self, mutex: &Mutex) {
        unsafe {
            let lock = self.lock.get();
            let seq = self.seq.get();

            if *lock != mutex.lock.get() {
                if *lock != ptr::null_mut() {
                    panic!("Condvar used with more than one Mutex");
                }

                atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize);
            }

            mutex_unlock(*lock);

            let _ = futex(seq, FUTEX_WAIT, *seq, 0, ptr::null_mut());

            while atomic_xchg(*lock, 2) != 0 {
                let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut());
            }
        }
    }

    #[inline]
    pub fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
        ::sys_common::util::dumb_print(format_args!("condvar wait_timeout\n"));
        unimplemented!();
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        *self.lock.get() = ptr::null_mut();
        *self.seq.get() = 0;
    }
}

unsafe impl Send for Condvar {}

unsafe impl Sync for Condvar {}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Macros for deriving `VertexFormat` and `ShaderParam`.

#[macro_export]
macro_rules! gfx_vertex {
    ($name:ident {
        $($gl_name:ident@ $field:ident: $ty:ty,)*
    }) => {
        #[derive(Clone, Copy, Debug)]
        pub struct $name {
            $(pub $field: $ty,)*
        }
        impl $crate::VertexFormat for $name {
            fn generate<R: $crate::Resources>(buffer: &$crate::handle::Buffer<R, $name>)
                        -> Vec<$crate::Attribute<R>> {
                use std::mem::size_of;
                use $crate::attrib::{Offset, Stride};
                use $crate::attrib::format::ToFormat;
                let stride = size_of::<$name>() as Stride;
                let mut offset = 0 as Offset;
                let mut attributes = Vec::new();
                $(
                    let (count, etype) = <$ty as ToFormat>::describe();
                    let format = $crate::attrib::Format {
                        elem_count: count,
                        elem_type: etype,
                        offset: offset,
                        stride: stride,
                        instance_rate: 0,
                    };
                    attributes.push($crate::Attribute {
                        name: stringify!($gl_name).to_string(),
                        format: format,
                        buffer: buffer.raw().clone(),
                    });
                    offset += size_of::<$ty>() as Offset;
                )*
                assert_eq!(offset, stride as Offset);
                attributes
            }
        }
    }
}

#[macro_export]
macro_rules! gfx_parameters {
    ($name:ident {
        $($gl_name:ident@ $field:ident: $ty:ty,)*
    }) => {
        #[derive(Clone, Debug)]
        pub struct $name<R: $crate::Resources> {
            $(pub $field: $ty,)*
            pub _r: ::std::marker::PhantomData<R>,
        }

        impl<R: $crate::Resources> $crate::shade::ShaderParam for $name<R> {
            type Resources = R;
            type Link = ($((Option<$crate::shade::ParameterId>, ::std::marker::PhantomData<$ty>),)*);

            fn create_link(_: Option<&$name<R>>, info: &$crate::ProgramInfo)
                           -> Result<Self::Link, $crate::shade::ParameterError>
            {
                use $crate::shade::Parameter;
                $(
                    let mut $field = None;
                )*
                // scan uniforms
                for (i, u) in info.uniforms.iter().enumerate() {
                    match &u.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_uniform(u) {
                                return Err($crate::shade::ParameterError::BadUniform(u.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingUniform(u.name.clone()))
                    }
                }
                // scan uniform blocks
                for (i, b) in info.blocks.iter().enumerate() {
                    match &b.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_block(b) {
                                return Err($crate::shade::ParameterError::BadBlock(b.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingBlock(b.name.clone()))
                    }
                }
                // scan textures
                for (i, t) in info.textures.iter().enumerate() {
                    match &t.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_texture(t) {
                                return Err($crate::shade::ParameterError::BadBlock(t.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingBlock(t.name.clone()))
                    }
                }
                Ok(( $(($field, ::std::marker::PhantomData),)* ))
            }

            fn fill_params(&self, link: &Self::Link, storage: &mut $crate::ParamStorage<R>) {
                use $crate::shade::Parameter;
                let &($(($field, _),)*) = link;
                $(
                    if let Some(id) = $field {
                        self.$field.put(id, storage);
                    }
                )*
            }
        }
    }
}
<commit_msg>Auto merge of #808 - red75prime:vertexfix, r=csherratt<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Macros for deriving `VertexFormat` and `ShaderParam`.

#[macro_export]
macro_rules! gfx_vertex {
    ($name:ident {
        $($gl_name:ident@ $field:ident: $ty:ty,)*
    }) => {
        #[derive(Clone, Copy, Debug)]
        pub struct $name {
            $(pub $field: $ty,)*
        }
        impl $crate::VertexFormat for $name {
            fn generate<R: $crate::Resources>(buffer: &$crate::handle::Buffer<R, $name>)
                        -> Vec<$crate::Attribute<R>> {
                use std::mem::{size_of, forget};
                use $crate::attrib::{Offset, Stride};
                use $crate::attrib::format::ToFormat;
                let stride = size_of::<$name>() as Stride;
                let mut attributes = Vec::new();
                $(
                    let (count, etype) = <$ty as ToFormat>::describe();
                    let tmp: $name = unsafe{ ::std::mem::uninitialized() };
                    let format = $crate::attrib::Format {
                        elem_count: count,
                        elem_type: etype,
                        offset: ((&tmp.$field as *const _ as usize) - (&tmp as *const _ as usize)) as Offset,
                        stride: stride,
                        instance_rate: 0,
                    };
                    forget(tmp);
                    attributes.push($crate::Attribute {
                        name: stringify!($gl_name).to_string(),
                        format: format,
                        buffer: buffer.raw().clone(),
                    });
                )*
                attributes
            }
        }
    }
}

#[macro_export]
macro_rules! gfx_parameters {
    ($name:ident {
        $($gl_name:ident@ $field:ident: $ty:ty,)*
    }) => {
        #[derive(Clone, Debug)]
        pub struct $name<R: $crate::Resources> {
            $(pub $field: $ty,)*
            pub _r: ::std::marker::PhantomData<R>,
        }

        impl<R: $crate::Resources> $crate::shade::ShaderParam for $name<R> {
            type Resources = R;
            type Link = ($((Option<$crate::shade::ParameterId>, ::std::marker::PhantomData<$ty>),)*);

            fn create_link(_: Option<&$name<R>>, info: &$crate::ProgramInfo)
                           -> Result<Self::Link, $crate::shade::ParameterError>
            {
                use $crate::shade::Parameter;
                $(
                    let mut $field = None;
                )*
                // scan uniforms
                for (i, u) in info.uniforms.iter().enumerate() {
                    match &u.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_uniform(u) {
                                return Err($crate::shade::ParameterError::BadUniform(u.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingUniform(u.name.clone()))
                    }
                }
                // scan uniform blocks
                for (i, b) in info.blocks.iter().enumerate() {
                    match &b.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_block(b) {
                                return Err($crate::shade::ParameterError::BadBlock(b.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingBlock(b.name.clone()))
                    }
                }
                // scan textures
                for (i, t) in info.textures.iter().enumerate() {
                    match &t.name[..] {
                        $(
                        stringify!($gl_name) => {
                            if !<$ty as Parameter<R>>::check_texture(t) {
                                return Err($crate::shade::ParameterError::BadBlock(t.name.clone()))
                            }
                            $field = Some(i as $crate::shade::ParameterId);
                        },
                        )*
                        _ => return Err($crate::shade::ParameterError::MissingBlock(t.name.clone()))
                    }
                }
                Ok(( $(($field, ::std::marker::PhantomData),)* ))
            }

            fn fill_params(&self, link: &Self::Link, storage: &mut $crate::ParamStorage<R>) {
                use $crate::shade::Parameter;
                let &($(($field, _),)*) = link;
                $(
                    if let Some(id) = $field {
                        self.$field.put(id, storage);
                    }
                )*
            }
        }
    }
}
<|endoftext|>