<commit_before>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::client::BulkResponse;
use crate::eve::Eve;
use crate::logger::log;

#[derive(Clone, Debug)]
pub struct Importer {
    index: String,
    queue: Vec<String>,
    client: crate::elastic::Client,
}

impl Importer {
    pub fn new(index: &str, client: crate::elastic::Client) -> Self {
        Self {
            index: index.to_string(),
            queue: Vec::new(),
            client: client,
        }
    }

    pub fn pending(&self) -> usize {
        self.queue.len() / 2
    }

    pub async fn submit(
        &mut self,
        mut event: serde_json::Value,
    ) -> anyhow::Result<(), Box<dyn std::error::Error + Send + Sync>> {
        let ts = event.timestamp().unwrap();
        let index = format!("{}-{}", self.index, ts.format("%Y.%m.%d"));
        let event_id = ulid::Ulid::from_datetime(ts).to_string();
        let at_timestamp = crate::elastic::format_timestamp(ts);
        event["@timestamp"] = at_timestamp.into();

        let mut header = serde_json::json!({
            "index": {
                "_index": index,
                "_id": event_id,
            }
        });

        let version = self.client.get_version().await?;
        if version.major < 7 {
            header["index"]["_type"] = "_doc".into();
        }

        self.queue.push(header.to_string());
        self.queue.push(event.to_string());

        Ok(())
    }

    pub async fn commit(&mut self) -> anyhow::Result<usize> {
        let n = self.pending();
        self.queue.push("".to_string());
        let mut body = self.queue.join("\n");
        body.push('\n');
        log::trace!(
            "Sending Elasticsearch bulk request: bytes={}, events={}",
            body.len(),
            self.queue.len() / 2,
        );
        let request = self.client.post("_bulk")?.body(body);
        let response = request.send().await?;
        let body_text = response.text().await?;
        let body: BulkResponse = serde_json::from_str(&body_text)?;
        if body.has_error() {
            if let Some(error) = body.first_error() {
                log::error!(
                    "Elasticsearch one of more errors to the commit operation, first error: {}",
                    error
                );
                return Err(anyhow!("elasticsearch commit error: {}", error));
            } else {
                log::error!("Elasticsearch reported errors during commit: {}", body_text);
                return Err(anyhow!("elasticsearch commit error: {}", body_text));
            }
        }
        self.queue.truncate(0);
        Ok(n)
    }
}
<commit_msg>elastic: use bulk create instead of bulk index<commit_after>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::client::BulkResponse;
use crate::eve::Eve;
use crate::logger::log;

#[derive(Clone, Debug)]
pub struct Importer {
    index: String,
    queue: Vec<String>,
    client: crate::elastic::Client,
}

impl Importer {
    pub fn new(index: &str, client: crate::elastic::Client) -> Self {
        Self {
            index: index.to_string(),
            queue: Vec::new(),
            client: client,
        }
    }

    pub fn pending(&self) -> usize {
        self.queue.len() / 2
    }

    pub async fn submit(
        &mut self,
        mut event: serde_json::Value,
    ) -> anyhow::Result<(), Box<dyn std::error::Error + Send + Sync>> {
        let ts = event.timestamp().unwrap();
        let index = format!("{}-{}", self.index, ts.format("%Y.%m.%d"));
        let event_id = ulid::Ulid::from_datetime(ts).to_string();
        let at_timestamp = crate::elastic::format_timestamp(ts);
        event["@timestamp"] = at_timestamp.into();

        let mut header = serde_json::json!({
            "create": {
                "_index": index,
                "_id": event_id,
            }
        });

        let version = self.client.get_version().await?;
        if version.major < 7 {
            header["create"]["_type"] = "_doc".into();
        }

        self.queue.push(header.to_string());
        self.queue.push(event.to_string());

        Ok(())
    }

    pub async fn commit(&mut self) -> anyhow::Result<usize> {
        let n = self.pending();
        self.queue.push("".to_string());
        let mut body = self.queue.join("\n");
        body.push('\n');
        log::trace!(
            "Sending Elasticsearch bulk request: bytes={}, events={}",
            body.len(),
            self.queue.len() / 2,
        );
        let request = self.client.post("_bulk")?.body(body);
        let response = request.send().await?;
        let body_text = response.text().await?;
        let body: BulkResponse = serde_json::from_str(&body_text)?;
        if body.has_error() {
            if let Some(error) = body.first_error() {
                log::error!(
                    "Elasticsearch one of more errors to the commit operation, first error: {}",
                    error
                );
                return Err(anyhow!("elasticsearch commit error: {}", error));
            } else {
                log::error!("Elasticsearch reported errors during commit: {}", body_text);
                return Err(anyhow!("elasticsearch commit error: {}", body_text));
            }
        }
        self.queue.truncate(0);
        Ok(n)
    }
}
<|endoftext|>


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

use std::str;

use router::Router;
use iron::prelude::*;
use bodyparser;
use exonum::api::{Api, ApiError};
use exonum::crypto::{CryptoHash, PublicKey, SecretKey, Hash};
use exonum::blockchain::{Blockchain, StoredConfiguration, Schema as CoreSchema};
use exonum::storage::StorageValue;
use exonum::node::TransactionSend;
use exonum::encoding::serialize::json::reexport as serde_json;
use exonum::helpers::Height;

use super::{ProposeData, Propose, Vote, Schema};

pub type VotesInfo = Option<Vec<Option<Vote>>>;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConfigHashInfo {
    pub hash: Hash,
    pub config: StoredConfiguration,
    pub propose: Option<Hash>,
    pub votes: VotesInfo,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ProposeHashInfo {
    pub hash: Hash,
    pub propose_data: ProposeData,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConfigInfo {
    pub committed_config: Option<StoredConfiguration>,
    pub propose: Option<ProposeData>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ProposeResponse {
    pub tx_hash: Hash,
    pub cfg_hash: Hash,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct VoteResponse {
    pub tx_hash: Hash,
}

#[derive(Clone)]
pub struct PrivateApi<T: TransactionSend + Clone> {
    pub channel: T,
    pub config: (PublicKey, SecretKey),
}

#[derive(Clone)]
pub struct PublicApi {
    pub blockchain: Blockchain,
}

/// Filter for stored configurations.
struct Filter {
    previous_cfg_hash: Option<Hash>,
    actual_from: Option<Height>,
}

impl Filter {
    /// Checks if a supplied configuration satisfies this filter.
    fn test(&self, cfg: &StoredConfiguration) -> bool {
        if let Some(ref prev) = self.previous_cfg_hash {
            if cfg.previous_cfg_hash != *prev {
                return false;
            }
        }

        if let Some(ref from_height) = self.actual_from {
            if cfg.actual_from < *from_height {
                return false;
            }
        }

        true
    }
}

impl PublicApi {
    fn config_with_proofs(&self, config: StoredConfiguration) -> ConfigHashInfo {
        let propose = Schema::new(self.blockchain.snapshot())
            .propose(&config.hash())
            .map(|p| p.hash());
        let votes = self.votes_for_propose(&config.hash());
        ConfigHashInfo {
            hash: config.hash(),
            config,
            propose,
            votes,
        }
    }

    fn actual_config(&self) -> ConfigHashInfo {
        let snapshot = self.blockchain.snapshot();
        let configuration_schema = CoreSchema::new(&snapshot);
        let actual_cfg = configuration_schema.actual_configuration();
        self.config_with_proofs(actual_cfg)
    }

    fn following_config(&self) -> Option<ConfigHashInfo> {
        CoreSchema::new(self.blockchain.snapshot())
            .following_configuration()
            .map(|following_cfg| self.config_with_proofs(following_cfg))
    }

    fn config_by_hash(&self, hash: &Hash) -> ConfigInfo {
        let snapshot = self.blockchain.snapshot();
        let committed_config = CoreSchema::new(&snapshot).configs().get(hash);
        let propose = Schema::new(&snapshot).propose_data_by_config_hash().get(
            hash,
        );

        ConfigInfo {
            committed_config,
            propose,
        }
    }

    fn votes_for_propose(&self, config_hash: &Hash) -> VotesInfo {
        let schema = Schema::new(self.blockchain.snapshot());

        if schema.propose_data_by_config_hash().contains(config_hash) {
            Some(schema.votes(config_hash))
        } else {
            None
        }
    }

    #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
    fn all_proposes(&self, filter: &Filter) -> Vec<ProposeHashInfo> {
        let schema = Schema::new(self.blockchain.snapshot());
        let index = schema.config_hash_by_ordinal();
        let proposes_by_hash = schema.propose_data_by_config_hash();

        let proposes = index
            .iter()
            .map(|cfg_hash| {
                let propose_data = proposes_by_hash.get(&cfg_hash).expect(&format!(
                    "Not found propose for following cfg_hash: {:?}",
                    cfg_hash
                ));

                (cfg_hash, propose_data)
            })
            .filter(|&(_, ref propose_data)| {
                let cfg = <StoredConfiguration as StorageValue>::from_bytes(
                    propose_data.tx_propose().cfg().as_bytes().into(),
                );
                filter.test(&cfg)
            })
            .map(|(hash, propose_data)| {
                ProposeHashInfo { hash, propose_data }
            })
            .collect();
        proposes
    }

    #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
    fn all_committed(&self, filter: &Filter) -> Vec<ConfigHashInfo> {
        let core_schema = CoreSchema::new(self.blockchain.snapshot());
        let actual_from = core_schema.configs_actual_from();
        let configs = core_schema.configs();

        let committed_configs = actual_from
            .iter()
            .map(|config_ref| {
                let config_hash = config_ref.cfg_hash();
                configs.get(config_hash).expect(&format!(
                    "Config with hash {:?} is absent in configs table",
                    config_hash
                ))
            })
            .filter(|config| filter.test(config))
            .map(|config| self.config_with_proofs(config))
            .collect();
        committed_configs
    }

    fn retrieve_params(
        &self,
        request: &mut Request,
    ) -> Result<(Option<Hash>, Option<Height>), ApiError> {
        let previous_cfg_hash: Option<Hash> = self.optional_param(request, "previous_cfg_hash")?;
        let actual_from: Option<Height> = self.optional_param(request, "actual_from")?;
        Ok((previous_cfg_hash, actual_from))
    }
}

impl<T> PrivateApi<T>
where
    T: TransactionSend + Clone,
{
    fn put_config_propose(&self, cfg: StoredConfiguration) -> Result<ProposeResponse, ApiError> {
        let cfg_hash = cfg.hash();
        let config_propose = Propose::new(
            &self.config.0,
            str::from_utf8(cfg.into_bytes().as_slice()).unwrap(),
            &self.config.1,
        );
        let tx_hash = config_propose.hash();
        let ch = self.channel.clone();
        ch.send(Box::new(config_propose))?;
        let res = ProposeResponse { tx_hash, cfg_hash };
        Ok(res)
    }

    fn put_config_vote(&self, cfg_hash: &Hash) -> Result<VoteResponse, ApiError> {
        let config_vote = Vote::new(&self.config.0, cfg_hash, &self.config.1);
        let tx_hash = config_vote.hash();
        let ch = self.channel.clone();
        ch.send(Box::new(config_vote))?;
        let res = VoteResponse { tx_hash };
        Ok(res)
    }
}

impl Api for PublicApi {
    fn wire(&self, router: &mut Router) {

        let self_ = self.clone();
        let config_actual = move |_: &mut Request| -> IronResult<Response> {
            let info = self_.actual_config();
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        let self_ = self.clone();
        let config_following = move |_: &mut Request| -> IronResult<Response> {
            let info = self_.following_config();
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        let self_ = self.clone();
        let config_by_hash = move |req: &mut Request| -> IronResult<Response> {
            let hash: Hash = self_.url_fragment(req, "hash")?;
            let info = self_.config_by_hash(&hash);
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        let self_ = self.clone();
        let votes_for_propose = move |req: &mut Request| -> IronResult<Response> {
            let propose_cfg_hash: Hash = self_.url_fragment(req, "hash")?;
            let info = self_.votes_for_propose(&propose_cfg_hash);
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        let self_ = self.clone();
        let all_proposes = move |req: &mut Request| -> IronResult<Response> {
            let (previous_cfg_hash, actual_from) = self_.retrieve_params(req)?;
            let info = self_.all_proposes(&Filter {
                previous_cfg_hash,
                actual_from,
            });
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        let self_ = self.clone();
        let all_committed = move |req: &mut Request| -> IronResult<Response> {
            let (previous_cfg_hash, actual_from) = self_.retrieve_params(req)?;
            let info = self_.all_committed(&Filter {
                previous_cfg_hash,
                actual_from,
            });
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };
        router.get("/v1/configs/actual", config_actual, "config_actual");
        router.get(
            "/v1/configs/following",
            config_following,
            "config_following",
        );
        router.get("/v1/configs/:hash", config_by_hash, "config_by_hash");
        router.get(
            "/v1/configs/:hash/votes",
            votes_for_propose,
            "votes_for_propose",
        );
        router.get("/v1/configs/proposed", all_proposes, "all_proposes");
        router.get("/v1/configs/committed", all_committed, "all_committed");

    }
}

impl<T> Api for PrivateApi<T>
where
    T: 'static + TransactionSend + Clone,
{
    fn wire(&self, router: &mut Router) {
        let self_ = self.clone();
        let put_config_propose = move |req: &mut Request| -> IronResult<Response> {
            match req.get::<bodyparser::Struct<StoredConfiguration>>() {
                Ok(Some(cfg)) => {
                    let info = self_.put_config_propose(cfg)?;
                    self_.ok_response(&serde_json::to_value(info).unwrap())
                }
                Ok(None) => Err(ApiError::BadRequest("Empty request body".into()))?,
                Err(e) => Err(ApiError::BadRequest(e.to_string()))?,
            }
        };

        let self_ = self.clone();
        let put_config_vote = move |req: &mut Request| -> IronResult<Response> {
            let propose_cfg_hash = self_.url_fragment(req, "hash")?;
            let info = self_.put_config_vote(&propose_cfg_hash)?;
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };
        router.post(
            "/v1/configs/postpropose",
            put_config_propose,
            "put_config_propose",
        );
        router.post(
            "/v1/configs/:hash/postvote",
            put_config_vote,
            "put_config_vote",
        );
    }
}
<commit_msg>Refactor filter initialization<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::str;

use router::Router;
use iron::prelude::*;
use bodyparser;
use exonum::api::{Api, ApiError};
use exonum::crypto::{CryptoHash, PublicKey, SecretKey, Hash};
use exonum::blockchain::{Blockchain, StoredConfiguration, Schema as CoreSchema};
use exonum::storage::StorageValue;
use exonum::node::TransactionSend;
use exonum::encoding::serialize::json::reexport as serde_json;
use exonum::helpers::Height;

use super::{ProposeData, Propose, Vote, Schema};

pub type VotesInfo = Option<Vec<Option<Vote>>>;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConfigHashInfo {
    pub hash: Hash,
    pub config: StoredConfiguration,
    pub propose: Option<Hash>,
    pub votes: VotesInfo,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ProposeHashInfo {
    pub hash: Hash,
    pub propose_data: ProposeData,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConfigInfo {
    pub committed_config: Option<StoredConfiguration>,
    pub propose: Option<ProposeData>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ProposeResponse {
    pub tx_hash: Hash,
    pub cfg_hash: Hash,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct VoteResponse {
    pub tx_hash: Hash,
}

#[derive(Clone)]
pub struct PrivateApi<T: TransactionSend + Clone> {
    pub channel: T,
    pub config: (PublicKey, SecretKey),
}

#[derive(Clone)]
pub struct PublicApi {
    pub blockchain: Blockchain,
}

/// Filter for stored configurations.
struct Filter {
    previous_cfg_hash: Option<Hash>,
    actual_from: Option<Height>,
}

impl Filter {
    /// Checks if a supplied configuration satisfies this filter.
    fn test(&self, cfg: &StoredConfiguration) -> bool {
        if let Some(ref prev) = self.previous_cfg_hash {
            if cfg.previous_cfg_hash != *prev {
                return false;
            }
        }

        if let Some(ref from_height) = self.actual_from {
            if cfg.actual_from < *from_height {
                return false;
            }
        }

        true
    }
}

impl PublicApi {
    fn config_with_proofs(&self, config: StoredConfiguration) -> ConfigHashInfo {
        let propose = Schema::new(self.blockchain.snapshot())
            .propose(&config.hash())
            .map(|p| p.hash());
        let votes = self.votes_for_propose(&config.hash());
        ConfigHashInfo {
            hash: config.hash(),
            config,
            propose,
            votes,
        }
    }

    fn actual_config(&self) -> ConfigHashInfo {
        let snapshot = self.blockchain.snapshot();
        let configuration_schema = CoreSchema::new(&snapshot);
        let actual_cfg = configuration_schema.actual_configuration();
        self.config_with_proofs(actual_cfg)
    }

    fn following_config(&self) -> Option<ConfigHashInfo> {
        CoreSchema::new(self.blockchain.snapshot())
            .following_configuration()
            .map(|following_cfg| self.config_with_proofs(following_cfg))
    }

    fn config_by_hash(&self, hash: &Hash) -> ConfigInfo {
        let snapshot = self.blockchain.snapshot();
        let committed_config = CoreSchema::new(&snapshot).configs().get(hash);
        let propose = Schema::new(&snapshot).propose_data_by_config_hash().get(
            hash,
        );

        ConfigInfo {
            committed_config,
            propose,
        }
    }

    fn votes_for_propose(&self, config_hash: &Hash) -> VotesInfo {
        let schema = Schema::new(self.blockchain.snapshot());

        if schema.propose_data_by_config_hash().contains(config_hash) {
            Some(schema.votes(config_hash))
        } else {
            None
        }
    }

    #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
    fn all_proposes(&self, filter: &Filter) -> Vec<ProposeHashInfo> {
        let schema = Schema::new(self.blockchain.snapshot());
        let index = schema.config_hash_by_ordinal();
        let proposes_by_hash = schema.propose_data_by_config_hash();

        let proposes = index
            .iter()
            .map(|cfg_hash| {
                let propose_data = proposes_by_hash.get(&cfg_hash).expect(&format!(
                    "Not found propose for following cfg_hash: {:?}",
                    cfg_hash
                ));

                (cfg_hash, propose_data)
            })
            .filter(|&(_, ref propose_data)| {
                let cfg = <StoredConfiguration as StorageValue>::from_bytes(
                    propose_data.tx_propose().cfg().as_bytes().into(),
                );
                filter.test(&cfg)
            })
            .map(|(hash, propose_data)| {
                ProposeHashInfo { hash, propose_data }
            })
            .collect();
        proposes
    }

    #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
    fn all_committed(&self, filter: &Filter) -> Vec<ConfigHashInfo> {
        let core_schema = CoreSchema::new(self.blockchain.snapshot());
        let actual_from = core_schema.configs_actual_from();
        let configs = core_schema.configs();

        let committed_configs = actual_from
            .iter()
            .map(|config_ref| {
                let config_hash = config_ref.cfg_hash();
                configs.get(config_hash).expect(&format!(
                    "Config with hash {:?} is absent in configs table",
                    config_hash
                ))
            })
            .filter(|config| filter.test(config))
            .map(|config| self.config_with_proofs(config))
            .collect();
        committed_configs
    }

    fn retrieve_filter(&self, request: &mut Request) -> Result<Filter, ApiError> {
        let previous_cfg_hash: Option<Hash> = self.optional_param(request, "previous_cfg_hash")?;
        let actual_from: Option<Height> = self.optional_param(request, "actual_from")?;
        Ok(Filter {
            previous_cfg_hash,
            actual_from,
        })
    }
}

impl<T> PrivateApi<T>
where
    T: TransactionSend + Clone,
{
    fn put_config_propose(&self, cfg: StoredConfiguration) -> Result<ProposeResponse, ApiError> {
        let cfg_hash = cfg.hash();
        let config_propose = Propose::new(
            &self.config.0,
            str::from_utf8(cfg.into_bytes().as_slice()).unwrap(),
            &self.config.1,
        );
        let tx_hash = config_propose.hash();
        let ch = self.channel.clone();
        ch.send(Box::new(config_propose))?;
        let res = ProposeResponse { tx_hash, cfg_hash };
        Ok(res)
    }

    fn put_config_vote(&self, cfg_hash: &Hash) -> Result<VoteResponse, ApiError> {
        let config_vote = Vote::new(&self.config.0, cfg_hash, &self.config.1);
        let tx_hash = config_vote.hash();
        let ch = self.channel.clone();
        ch.send(Box::new(config_vote))?;
        let res = VoteResponse { tx_hash };
        Ok(res)
    }
}

impl Api for PublicApi {
    fn wire(&self, router: &mut Router) {
        let self_ = self.clone();
        let config_actual = move |_: &mut Request| -> IronResult<Response> {
            let info = self_.actual_config();
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        let self_ = self.clone();
        let config_following = move |_: &mut Request| -> IronResult<Response> {
            let info = self_.following_config();
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        let self_ = self.clone();
        let config_by_hash = move |req: &mut Request| -> IronResult<Response> {
            let hash: Hash = self_.url_fragment(req, "hash")?;
            let info = self_.config_by_hash(&hash);
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        let self_ = self.clone();
        let votes_for_propose = move |req: &mut Request| -> IronResult<Response> {
            let propose_cfg_hash: Hash = self_.url_fragment(req, "hash")?;
            let info = self_.votes_for_propose(&propose_cfg_hash);
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        let self_ = self.clone();
        let all_proposes = move |req: &mut Request| -> IronResult<Response> {
            let info = self_.all_proposes(&self_.retrieve_filter(req)?);
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        let self_ = self.clone();
        let all_committed = move |req: &mut Request| -> IronResult<Response> {
            let info = self_.all_committed(&self_.retrieve_filter(req)?);
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        router.get("/v1/configs/actual", config_actual, "config_actual");
        router.get(
            "/v1/configs/following",
            config_following,
            "config_following",
        );
        router.get("/v1/configs/:hash", config_by_hash, "config_by_hash");
        router.get(
            "/v1/configs/:hash/votes",
            votes_for_propose,
            "votes_for_propose",
        );
        router.get("/v1/configs/proposed", all_proposes, "all_proposes");
        router.get("/v1/configs/committed", all_committed, "all_committed");
    }
}

impl<T> Api for PrivateApi<T>
where
    T: 'static + TransactionSend + Clone,
{
    fn wire(&self, router: &mut Router) {
        let self_ = self.clone();
        let put_config_propose = move |req: &mut Request| -> IronResult<Response> {
            match req.get::<bodyparser::Struct<StoredConfiguration>>() {
                Ok(Some(cfg)) => {
                    let info = self_.put_config_propose(cfg)?;
                    self_.ok_response(&serde_json::to_value(info).unwrap())
                }
                Ok(None) => Err(ApiError::BadRequest("Empty request body".into()))?,
                Err(e) => Err(ApiError::BadRequest(e.to_string()))?,
            }
        };

        let self_ = self.clone();
        let put_config_vote = move |req: &mut Request| -> IronResult<Response> {
            let propose_cfg_hash = self_.url_fragment(req, "hash")?;
            let info = self_.put_config_vote(&propose_cfg_hash)?;
            self_.ok_response(&serde_json::to_value(info).unwrap())
        };

        router.post(
            "/v1/configs/postpropose",
            put_config_propose,
            "put_config_propose",
        );
        router.post(
            "/v1/configs/:hash/postvote",
            put_config_vote,
            "put_config_vote",
        );
    }
}
<|endoftext|>


<commit_before>use super::heap::ObjectPointer;
use crate::{compiler::lir::ChunkIndex, builtin_functions::BuiltinFunction};
use im::HashMap;
use itertools::Itertools;
use std::fmt::{self, Display, Formatter};

/// A self-contained value. Unlike objects, these are not tied to a running VM,
/// which makes them useful for being sent through channels between multiple
/// reference-counted heaps, for example ones running concurrently logically, on
/// other cores, or on different computers.
///
/// VMs can import these values to turn them into heap-contained,
/// reference-counted objects. They can export objects from the heap into
/// self-contained values.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Value {
    Int(u64),
    Text(String),
    Symbol(String),
    Struct(HashMap<Value, Value>),
    Closure {
        captured: Vec<ObjectPointer>,
        body: ChunkIndex,
    },
    Builtin(BuiltinFunction)
}

impl Value {
    pub fn nothing() -> Value {
        Value::Symbol("Nothing".to_owned())
    }
    pub fn list(items: Vec<Value>) -> Self {
        let items = items
            .into_iter()
            .enumerate()
            .map(|(index, it)| (Value::Int(index as u64), it))
            .collect();
        Value::Struct(items)
    }

    pub fn try_into_int(self) -> Result<u64, Value> {
        match self {
            Value::Int(int) => Ok(int),
            it => Err(it),
        }
    }
    pub fn try_into_text(self) -> Result<String, Value> {
        match self {
            Value::Text(text) => Ok(text),
            it => Err(it),
        }
    }
    pub fn try_into_symbol(self) -> Result<String, Value> {
        match self {
            Value::Symbol(symbol) => Ok(symbol),
            it => Err(it),
        }
    }
    pub fn try_into_struct(self) -> Result<HashMap<Value, Value>, Value> {
        match self {
            Value::Struct(entries) => Ok(entries),
            it => Err(it),
        }
    }
    pub fn try_into_closure(self) -> Result<(Vec<ObjectPointer>, ChunkIndex), Value> {
        match self {
            Value::Closure { captured, body } => Ok((captured, body)),
            it => Err(it),
        }
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Value::Int(int) => write!(f, "{}", int),
            Value::Text(text) => write!(f, "{:?}", text),
            Value::Symbol(symbol) => write!(f, "{}", symbol),
            Value::Struct(entries) => write!(
                f,
                "{{ {} }}",
                entries
                    .iter()
                    .map(|(key, value)| format!("{}: {}", key, value))
                    .join(", ")
            ),
            Value::Closure { body, .. } => {
                write!(f, "{{{}}}", body)
            }
            Value::Builtin(builtin) => {
                write!(f, "builtin{:?}", builtin)
            }
        }
    }
}

impl From<u64> for Value {
    fn from(value: u64) -> Self {
        Value::Int(value)
    }
}
impl From<String> for Value {
    fn from(value: String) -> Self {
        Value::Text(value)
    }
}
impl From<bool> for Value {
    fn from(it: bool) -> Self {
        Value::Symbol(if it { "True" } else { "False" }.to_string())
    }
}
<commit_msg>Remove unused methods on Value<commit_after>use super::heap::ObjectPointer;
use crate::{compiler::lir::ChunkIndex, builtin_functions::BuiltinFunction};
use im::HashMap;
use itertools::Itertools;
use std::fmt::{self, Display, Formatter};

/// A self-contained value. Unlike objects, these are not tied to a running VM,
/// which makes them useful for being sent through channels between multiple
/// reference-counted heaps, for example ones running concurrently logically, on
/// other cores, or on different computers.
///
/// VMs can import these values to turn them into heap-contained,
/// reference-counted objects. They can export objects from the heap into
/// self-contained values.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Value {
    Int(u64),
    Text(String),
    Symbol(String),
    Struct(HashMap<Value, Value>),
    Closure {
        captured: Vec<ObjectPointer>,
        body: ChunkIndex,
    },
    Builtin(BuiltinFunction)
}

impl Value {
    pub fn nothing() -> Value {
        Value::Symbol("Nothing".to_owned())
    }
    pub fn list(items: Vec<Value>) -> Self {
        let items = items
            .into_iter()
            .enumerate()
            .map(|(index, it)| (Value::Int(index as u64), it))
            .collect();
        Value::Struct(items)
    }

    pub fn try_into_text(self) -> Result<String, Value> {
        match self {
            Value::Text(text) => Ok(text),
            it => Err(it),
        }
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Value::Int(int) => write!(f, "{}", int),
            Value::Text(text) => write!(f, "{:?}", text),
            Value::Symbol(symbol) => write!(f, "{}", symbol),
            Value::Struct(entries) => write!(
                f,
                "{{ {} }}",
                entries
                    .iter()
                    .map(|(key, value)| format!("{}: {}", key, value))
                    .join(", ")
            ),
            Value::Closure { body, .. } => {
                write!(f, "{{{}}}", body)
            }
            Value::Builtin(builtin) => {
                write!(f, "builtin{:?}", builtin)
            }
        }
    }
}

impl From<u64> for Value {
    fn from(value: u64) -> Self {
        Value::Int(value)
    }
}
impl From<String> for Value {
    fn from(value: String) -> Self {
        Value::Text(value)
    }
}
impl From<bool> for Value {
    fn from(it: bool) -> Self {
        Value::Symbol(if it { "True" } else { "False" }.to_string())
    }
}
<|endoftext|>


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

use std::old_io::{Command, IoError, OtherIoError};
use target::TargetOptions;

use self::Arch::*;

#[allow(non_camel_case_types)]
#[derive(Copy)]
pub enum Arch {
    Armv7,
    Armv7s,
    Arm64,
    I386,
    X86_64
}

impl Arch {
    pub fn to_string(&self) -> &'static str {
        match self {
            &Armv7 => "armv7",
            &Armv7s => "armv7s",
            &Arm64 => "arm64",
            &I386 => "i386",
            &X86_64 => "x86_64"
        }
    }
}

pub fn get_sdk_root(sdk_name: &str) -> String {
    let res = Command::new("xcrun")
                      .arg("--show-sdk-path")
                      .arg("-sdk")
                      .arg(sdk_name)
                      .spawn()
                      .and_then(|c| c.wait_with_output())
                      .and_then(|output| {
                          if output.status.success() {
                              Ok(String::from_utf8(output.output).unwrap())
                          } else {
                              Err(IoError {
                                  kind: OtherIoError,
                                  desc: "process exit with error",
                                  detail: String::from_utf8(output.error).ok()})
                          }
                      });

    match res {
        Ok(output) => output.trim().to_string(),
        Err(e) => panic!("failed to get {} SDK path: {}", sdk_name, e)
    }
}

fn pre_link_args(arch: Arch) -> Vec<String> {
    let sdk_name = match arch {
        Armv7 | Armv7s | Arm64 => "iphoneos",
        I386 | X86_64 => "iphonesimulator"
    };

    let arch_name = arch.to_string();

    vec!["-arch".to_string(), arch_name.to_string(),
         "-Wl,-syslibroot".to_string(), get_sdk_root(sdk_name)]
}

fn target_cpu(arch: Arch) -> String {
    match arch {
        X86_64 => "x86-64",
        _ => "generic",
    }.to_string()
}

pub fn opts(arch: Arch) -> TargetOptions {
    TargetOptions {
        cpu: target_cpu(arch),
        dynamic_linking: false,
        executables: true,
        // Although there is an experimental implementation of LLVM which
        // supports SS on armv7 it wasn't approved by Apple, see:
        // http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20140505/216350.html
        // It looks like it might be never accepted to upstream LLVM.
        //
        // SS might be also enabled on Arm64 as it has builtin support in LLVM
        // but I haven't tested it through yet
        morestack: false,
        pre_link_args: pre_link_args(arch),
        .. super::apple_base::opts()
    }
}
<commit_msg>Adjusting default CPUs for iOS<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::old_io::{Command, IoError, OtherIoError};
use target::TargetOptions;

use self::Arch::*;

#[allow(non_camel_case_types)]
#[derive(Copy)]
pub enum Arch {
    Armv7,
    Armv7s,
    Arm64,
    I386,
    X86_64
}

impl Arch {
    pub fn to_string(&self) -> &'static str {
        match self {
            &Armv7 => "armv7",
            &Armv7s => "armv7s",
            &Arm64 => "arm64",
            &I386 => "i386",
            &X86_64 => "x86_64"
        }
    }
}

pub fn get_sdk_root(sdk_name: &str) -> String {
    let res = Command::new("xcrun")
                      .arg("--show-sdk-path")
                      .arg("-sdk")
                      .arg(sdk_name)
                      .spawn()
                      .and_then(|c| c.wait_with_output())
                      .and_then(|output| {
                          if output.status.success() {
                              Ok(String::from_utf8(output.output).unwrap())
                          } else {
                              Err(IoError {
                                  kind: OtherIoError,
                                  desc: "process exit with error",
                                  detail: String::from_utf8(output.error).ok()})
                          }
                      });

    match res {
        Ok(output) => output.trim().to_string(),
        Err(e) => panic!("failed to get {} SDK path: {}", sdk_name, e)
    }
}

fn pre_link_args(arch: Arch) -> Vec<String> {
    let sdk_name = match arch {
        Armv7 | Armv7s | Arm64 => "iphoneos",
        I386 | X86_64 => "iphonesimulator"
    };

    let arch_name = arch.to_string();

    vec!["-arch".to_string(), arch_name.to_string(),
         "-Wl,-syslibroot".to_string(), get_sdk_root(sdk_name)]
}

fn target_cpu(arch: Arch) -> String {
    match arch {
        Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
        Armv7s => "cortex-a9",
        Arm64 => "cyclone",
        I386 => "generic",
        X86_64 => "x86-64",
    }.to_string()
}

pub fn opts(arch: Arch) -> TargetOptions {
    TargetOptions {
        cpu: target_cpu(arch),
        dynamic_linking: false,
        executables: true,
        // Although there is an experimental implementation of LLVM which
        // supports SS on armv7 it wasn't approved by Apple, see:
        // http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20140505/216350.html
        // It looks like it might be never accepted to upstream LLVM.
        //
        // SS might be also enabled on Arm64 as it has builtin support in LLVM
        // but I haven't tested it through yet
        morestack: false,
        pre_link_args: pre_link_args(arch),
        .. super::apple_base::opts()
    }
}
<|endoftext|>


<commit_before>use rustc::mir::visit::{PlaceContext, Visitor};
use rustc::mir::{
    Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind
};

use rustc_data_structures::fx::FxHashSet;

use crate::borrow_check::MirBorrowckCtxt;

impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
    /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes
    /// of the `unused_mut` lint.
    ///
    /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and
    ///  used from borrow checking. This function looks for assignments into these locals from
    ///  user-declared locals and adds those user-defined locals to the `used_mut` set. This can
    ///  occur due to a rare case involving upvars in closures.
    ///
    /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals
    ///  (not arguments) that have not already been marked as being used.
    ///  This function then looks for assignments from statements or the terminator into the locals
    ///  from this set and removes them from the set. This leaves only those locals that have not
    ///  been assigned to - this set is used as a proxy for locals that were not initialized due to
    ///  unreachable code. These locals are then considered "used" to silence the lint for them.
    ///  See #55344 for context.
    crate fn gather_used_muts(
        &mut self,
        temporary_used_locals: FxHashSet<Local>,
        mut never_initialized_mut_locals: FxHashSet<Local>,
    ) {
        {
            let mut visitor = GatherUsedMutsVisitor {
                temporary_used_locals,
                never_initialized_mut_locals: &mut never_initialized_mut_locals,
                mbcx: self,
            };
            visitor.visit_body(visitor.mbcx.mir);
        }

        // Take the union of the existed `used_mut` set with those variables we've found were
        // never initialized.
        debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals);
        self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect();
    }
}

/// MIR visitor for collecting used mutable variables.
/// The 'visit lifetime represents the duration of the MIR walk.
struct GatherUsedMutsVisitor<'visit, 'cx: 'visit, 'gcx: 'tcx, 'tcx: 'cx> {
    temporary_used_locals: FxHashSet<Local>,
    never_initialized_mut_locals: &'visit mut FxHashSet<Local>,
    mbcx: &'visit mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
}

impl GatherUsedMutsVisitor<'_, '_, '_, '_> {
    fn remove_never_initialized_mut_locals(&mut self, into: &Place) {
        // Remove any locals that we found were initialized from the
        // `never_initialized_mut_locals` set. At the end, the only remaining locals will
        // be those that were never initialized - we will consider those as being used as
        // they will either have been removed by unreachable code optimizations; or linted
        // as unused variables.
        if let Some(local) = into.base_local() {
            let _ = self.never_initialized_mut_locals.remove(&local);
        }
    }
}

impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'gcx, 'tcx> {
    fn visit_terminator_kind(
        &mut self,
        kind: &TerminatorKind<'tcx>,
        _location: Location,
    ) {
        debug!("visit_terminator_kind: kind={:?}", kind);
        match &kind {
            TerminatorKind::Call { destination: Some((into, _)), .. } => {
                self.remove_never_initialized_mut_locals(&into);
            },
            TerminatorKind::DropAndReplace { location, .. } => {
                self.remove_never_initialized_mut_locals(&location);
            },
            _ => {},
        }
    }

    fn visit_statement(
        &mut self,
        statement: &Statement<'tcx>,
        _location: Location,
    ) {
        match &statement.kind {
            StatementKind::Assign(into, _) => {
                if let Some(local) = into.base_local() {
                    debug!(
                        "visit_statement: statement={:?} local={:?} \
                         never_initialized_mut_locals={:?}",
                        statement, local, self.never_initialized_mut_locals
                    );
                }
                self.remove_never_initialized_mut_locals(into);
            },
            _ => {},
        }
    }

    fn visit_local(
        &mut self,
        local: &Local,
        place_context: PlaceContext,
        location: Location,
    ) {
        if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) {
            // Propagate the Local assigned at this Location as a used mutable local variable
            for moi in &self.mbcx.move_data.loc_map[location] {
                let mpi = &self.mbcx.move_data.moves[*moi].path;
                let path = &self.mbcx.move_data.move_paths[*mpi];
                debug!(
                    "assignment of {:?} to {:?}, adding {:?} to used mutable set",
                    path.place, local, path.place
                );
                if let Place::Base(PlaceBase::Local(user_local)) = path.place {
                    self.mbcx.used_mut.insert(user_local);
                }
            }
        }
    }
}
<commit_msg>Add anonymous lifetime to Place parameter<commit_after>use rustc::mir::visit::{PlaceContext, Visitor};
use rustc::mir::{
    Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind
};

use rustc_data_structures::fx::FxHashSet;

use crate::borrow_check::MirBorrowckCtxt;

impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
    /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes
    /// of the `unused_mut` lint.
    ///
    /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and
    ///  used from borrow checking. This function looks for assignments into these locals from
    ///  user-declared locals and adds those user-defined locals to the `used_mut` set. This can
    ///  occur due to a rare case involving upvars in closures.
    ///
    /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals
    ///  (not arguments) that have not already been marked as being used.
    ///  This function then looks for assignments from statements or the terminator into the locals
    ///  from this set and removes them from the set. This leaves only those locals that have not
    ///  been assigned to - this set is used as a proxy for locals that were not initialized due to
    ///  unreachable code. These locals are then considered "used" to silence the lint for them.
    ///  See #55344 for context.
    crate fn gather_used_muts(
        &mut self,
        temporary_used_locals: FxHashSet<Local>,
        mut never_initialized_mut_locals: FxHashSet<Local>,
    ) {
        {
            let mut visitor = GatherUsedMutsVisitor {
                temporary_used_locals,
                never_initialized_mut_locals: &mut never_initialized_mut_locals,
                mbcx: self,
            };
            visitor.visit_body(visitor.mbcx.mir);
        }

        // Take the union of the existed `used_mut` set with those variables we've found were
        // never initialized.
        debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals);
        self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect();
    }
}

/// MIR visitor for collecting used mutable variables.
/// The 'visit lifetime represents the duration of the MIR walk.
struct GatherUsedMutsVisitor<'visit, 'cx: 'visit, 'gcx: 'tcx, 'tcx: 'cx> {
    temporary_used_locals: FxHashSet<Local>,
    never_initialized_mut_locals: &'visit mut FxHashSet<Local>,
    mbcx: &'visit mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
}

impl GatherUsedMutsVisitor<'_, '_, '_, '_> {
    fn remove_never_initialized_mut_locals(&mut self, into: &Place<'_>) {
        // Remove any locals that we found were initialized from the
        // `never_initialized_mut_locals` set. At the end, the only remaining locals will
        // be those that were never initialized - we will consider those as being used as
        // they will either have been removed by unreachable code optimizations; or linted
        // as unused variables.
        if let Some(local) = into.base_local() {
            let _ = self.never_initialized_mut_locals.remove(&local);
        }
    }
}

impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'gcx, 'tcx> {
    fn visit_terminator_kind(
        &mut self,
        kind: &TerminatorKind<'tcx>,
        _location: Location,
    ) {
        debug!("visit_terminator_kind: kind={:?}", kind);
        match &kind {
            TerminatorKind::Call { destination: Some((into, _)), .. } => {
                self.remove_never_initialized_mut_locals(&into);
            },
            TerminatorKind::DropAndReplace { location, .. } => {
                self.remove_never_initialized_mut_locals(&location);
            },
            _ => {},
        }
    }

    fn visit_statement(
        &mut self,
        statement: &Statement<'tcx>,
        _location: Location,
    ) {
        match &statement.kind {
            StatementKind::Assign(into, _) => {
                if let Some(local) = into.base_local() {
                    debug!(
                        "visit_statement: statement={:?} local={:?} \
                         never_initialized_mut_locals={:?}",
                        statement, local, self.never_initialized_mut_locals
                    );
                }
                self.remove_never_initialized_mut_locals(into);
            },
            _ => {},
        }
    }

    fn visit_local(
        &mut self,
        local: &Local,
        place_context: PlaceContext,
        location: Location,
    ) {
        if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) {
            // Propagate the Local assigned at this Location as a used mutable local variable
            for moi in &self.mbcx.move_data.loc_map[location] {
                let mpi = &self.mbcx.move_data.moves[*moi].path;
                let path = &self.mbcx.move_data.move_paths[*mpi];
                debug!(
                    "assignment of {:?} to {:?}, adding {:?} to used mutable set",
                    path.place, local, path.place
                );
                if let Place::Base(PlaceBase::Local(user_local)) = path.place {
                    self.mbcx.used_mut.insert(user_local);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use ffi;
use LuaContext;

use AsLua;
use AsMutLua;
use Push;
use PushGuard;
use LuaRead;

/// Represents a table stored in the Lua context.
///
/// Loading this type mutably borrows the Lua context.
pub struct LuaTable<L> {
    table: L,
}

unsafe impl<L> AsLua for LuaTable<L> where L: AsLua {
    fn as_lua(&self) -> LuaContext {
        self.table.as_lua()
    }
}

unsafe impl<L> AsMutLua for LuaTable<L> where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.table.as_mut_lua()
    }
}

impl<L> LuaRead<L> for LuaTable<L> where L: AsMutLua {
    fn lua_read_at_position(mut lua: L, index: i32) -> Result<LuaTable<L>, L> {
        assert!(index == -1);   // FIXME: not sure if it's working
        if unsafe { ffi::lua_istable(lua.as_mut_lua().0, index) } {
            Ok(LuaTable { table: lua })
        } else {
            Err(lua)
        }
    }
}

/// Iterator that enumerates the content of a Lua table.
// while the LuaTableIterator is active, the current key is constantly pushed over the table
pub struct LuaTableIterator<'t, L: 't, K, V> where L: AsMutLua {
    table: &'t mut LuaTable<L>,
    finished: bool,     // if true, the key is not on the stack anymore
    marker: PhantomData<(K, V)>,
}

unsafe impl<'t, L, K, V> AsLua for LuaTableIterator<'t, L, K, V> where L: AsMutLua {
    fn as_lua(&self) -> LuaContext {
        self.table.as_lua()
    }
}

unsafe impl<'t, L, K, V> AsMutLua for LuaTableIterator<'t, L, K, V> where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.table.as_mut_lua()
    }
}

impl<L> LuaTable<L> where L: AsMutLua {
    /// Destroys the LuaTable and returns its inner Lua context. Useful when it takes Lua by value.
    pub fn into_inner(self) -> L {
        self.table
    }

    /// Iterates over the elements inside the table.
    pub fn iter<K, V>(&mut self) -> LuaTableIterator<L, K, V> {
        unsafe { ffi::lua_pushnil(self.table.as_mut_lua().0) };

        LuaTableIterator {
            table: self,
            finished: false,
            marker: PhantomData,
        }
    }

    /// Loads a value in the table given its index.
    pub fn get<'a, R, I>(&'a mut self, index: I) -> Option<R>
                         where R: LuaRead<PushGuard<&'a mut LuaTable<L>>>,
                               I: for<'b> Push<&'b mut &'a mut LuaTable<L>>
    {
        let mut me = self;
        index.push_to_lua(&mut me).forget();
        unsafe { ffi::lua_gettable(me.as_mut_lua().0, -2); }
        let guard = PushGuard { lua: me, size: 1 };
        LuaRead::lua_read(guard).ok()
    }

    /// Loads a value in the table, with the result capturing the table by value.
    pub fn into_get<'a, R, I>(self, index: I) -> Result<R, PushGuard<Self>>
        where R: LuaRead<PushGuard<LuaTable<L>>>,
              I: for<'b> Push<&'b mut LuaTable<L>>
    {
        let mut me = self;
        index.push_to_lua(&mut me).forget();
        unsafe { ffi::lua_gettable(me.as_mut_lua().0, -2); }
        let is_nil = unsafe { ffi::lua_isnil(me.as_mut_lua().0, -1) };
        let guard = PushGuard { lua: me, size: 1 };
        if is_nil {
            Err(guard)
        } else {
            LuaRead::lua_read(guard)
        }
    }

    /// Inserts or modifies an elements of the table.
    pub fn set<'s, I, V>(&'s mut self, index: I, value: V)
                         where I: for<'a> Push<&'a mut &'s mut LuaTable<L>>,
                               V: for<'a> Push<&'a mut &'s mut LuaTable<L>>
    {
        let mut me = self;
        index.push_to_lua(&mut me).forget();
        value.push_to_lua(&mut me).forget();
        unsafe { ffi::lua_settable(me.as_mut_lua().0, -3); }
    }

    /// Inserts an empty array, then loads it.
    pub fn empty_array<'s, I>(&'s mut self, index: I) -> LuaTable<PushGuard<&'s mut LuaTable<L>>>
                              where I: for<'a> Push<&'a mut &'s mut LuaTable<L>> + Clone
    {
        // TODO: cleaner implementation
        let mut me = self;
        index.clone().push_to_lua(&mut me).forget();
        Vec::<u8>::with_capacity(0).push_to_lua(&mut me).forget();
        unsafe { ffi::lua_settable(me.as_mut_lua().0, -3); }

        me.get(index).unwrap()
    }

    /// Obtains or create the metatable of the table.
    pub fn get_or_create_metatable(mut self) -> LuaTable<PushGuard<L>> {
        let result = unsafe { ffi::lua_getmetatable(self.table.as_mut_lua().0, -1) };

        if result == 0 {
            unsafe {
                ffi::lua_newtable(self.table.as_mut_lua().0);
                ffi::lua_setmetatable(self.table.as_mut_lua().0, -2);
                let r = ffi::lua_getmetatable(self.table.as_mut_lua().0, -1);
                assert!(r != 0);
            }
        }

        LuaTable {
            table: PushGuard { lua: self.table, size: 1 }
        }
    }
}

impl<'t, L, K, V> Iterator for LuaTableIterator<'t, L, K, V>
                  where L: AsMutLua + 't,
                        K: for<'i, 'j> LuaRead<&'i mut &'j mut LuaTableIterator<'t, L, K, V>> + 'static,
                        V: for<'i, 'j> LuaRead<&'i mut &'j mut LuaTableIterator<'t, L, K, V>> + 'static
{
    type Item = Option<(K, V)>;

    fn next(&mut self) -> Option<Option<(K,V)>> {
        if self.finished {
            return None;
        }

        // this call pushes the next key and value on the stack
        if unsafe { ffi::lua_next(self.table.as_mut_lua().0, -2) } == 0 {
            self.finished = true;
            return None;
        }

        let mut me = self;
        let key = LuaRead::lua_read_at_position(&mut me, -2).ok();
        let value = LuaRead::lua_read_at_position(&mut me, -1).ok();

        // removing the value, leaving only the key on the top of the stack
        unsafe { ffi::lua_pop(me.table.as_mut_lua().0, 1) };

        //
        if key.is_none() || value.is_none() {
            Some(None)
        } else {
            Some(Some((key.unwrap(), value.unwrap())))
        }
    }
}

impl<'t, L, K, V> Drop for LuaTableIterator<'t, L, K, V> where L: AsMutLua + 't {
    fn drop(&mut self) {
        if !self.finished {
            unsafe { ffi::lua_pop(self.table.table.as_mut_lua().0, 1) }
        }
    }
}
<commit_msg>Change LuaTable.get to adhere to nil = None<commit_after>use std::marker::PhantomData;

use ffi;
use LuaContext;

use AsLua;
use AsMutLua;
use Push;
use PushGuard;
use LuaRead;

/// Represents a table stored in the Lua context.
///
/// Loading this type mutably borrows the Lua context.
pub struct LuaTable<L> {
    table: L,
}

unsafe impl<L> AsLua for LuaTable<L> where L: AsLua {
    fn as_lua(&self) -> LuaContext {
        self.table.as_lua()
    }
}

unsafe impl<L> AsMutLua for LuaTable<L> where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.table.as_mut_lua()
    }
}

impl<L> LuaRead<L> for LuaTable<L> where L: AsMutLua {
    fn lua_read_at_position(mut lua: L, index: i32) -> Result<LuaTable<L>, L> {
        assert!(index == -1);   // FIXME: not sure if it's working
        if unsafe { ffi::lua_istable(lua.as_mut_lua().0, index) } {
            Ok(LuaTable { table: lua })
        } else {
            Err(lua)
        }
    }
}

/// Iterator that enumerates the content of a Lua table.
// while the LuaTableIterator is active, the current key is constantly pushed over the table
pub struct LuaTableIterator<'t, L: 't, K, V> where L: AsMutLua {
    table: &'t mut LuaTable<L>,
    finished: bool,     // if true, the key is not on the stack anymore
    marker: PhantomData<(K, V)>,
}

unsafe impl<'t, L, K, V> AsLua for LuaTableIterator<'t, L, K, V> where L: AsMutLua {
    fn as_lua(&self) -> LuaContext {
        self.table.as_lua()
    }
}

unsafe impl<'t, L, K, V> AsMutLua for LuaTableIterator<'t, L, K, V> where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.table.as_mut_lua()
    }
}

impl<L> LuaTable<L> where L: AsMutLua {
    /// Destroys the LuaTable and returns its inner Lua context. Useful when it takes Lua by value.
    pub fn into_inner(self) -> L {
        self.table
    }

    /// Iterates over the elements inside the table.
    pub fn iter<K, V>(&mut self) -> LuaTableIterator<L, K, V> {
        unsafe { ffi::lua_pushnil(self.table.as_mut_lua().0) };

        LuaTableIterator {
            table: self,
            finished: false,
            marker: PhantomData,
        }
    }

    /// Loads a value in the table given its index.
    pub fn get<'a, R, I>(&'a mut self, index: I) -> Option<R>
                         where R: LuaRead<PushGuard<&'a mut LuaTable<L>>>,
                               I: for<'b> Push<&'b mut &'a mut LuaTable<L>>
    {
        let mut me = self;
        index.push_to_lua(&mut me).forget();
        unsafe { ffi::lua_gettable(me.as_mut_lua().0, -2); }
        if unsafe { ffi::lua_isnil(me.as_lua().0, -1) } {
            let _guard = PushGuard { lua: me, size: 1 };
            return None;
        }
        let guard = PushGuard { lua: me, size: 1 };
        LuaRead::lua_read(guard).ok()
    }

    /// Loads a value in the table, with the result capturing the table by value.
    pub fn into_get<'a, R, I>(self, index: I) -> Result<R, PushGuard<Self>>
        where R: LuaRead<PushGuard<LuaTable<L>>>,
              I: for<'b> Push<&'b mut LuaTable<L>>
    {
        let mut me = self;
        index.push_to_lua(&mut me).forget();
        unsafe { ffi::lua_gettable(me.as_mut_lua().0, -2); }
        let is_nil = unsafe { ffi::lua_isnil(me.as_mut_lua().0, -1) };
        let guard = PushGuard { lua: me, size: 1 };
        if is_nil {
            Err(guard)
        } else {
            LuaRead::lua_read(guard)
        }
    }

    /// Inserts or modifies an elements of the table.
    pub fn set<'s, I, V>(&'s mut self, index: I, value: V)
                         where I: for<'a> Push<&'a mut &'s mut LuaTable<L>>,
                               V: for<'a> Push<&'a mut &'s mut LuaTable<L>>
    {
        let mut me = self;
        index.push_to_lua(&mut me).forget();
        value.push_to_lua(&mut me).forget();
        unsafe { ffi::lua_settable(me.as_mut_lua().0, -3); }
    }

    /// Inserts an empty array, then loads it.
    pub fn empty_array<'s, I>(&'s mut self, index: I) -> LuaTable<PushGuard<&'s mut LuaTable<L>>>
                              where I: for<'a> Push<&'a mut &'s mut LuaTable<L>> + Clone
    {
        // TODO: cleaner implementation
        let mut me = self;
        index.clone().push_to_lua(&mut me).forget();
        Vec::<u8>::with_capacity(0).push_to_lua(&mut me).forget();
        unsafe { ffi::lua_settable(me.as_mut_lua().0, -3); }

        me.get(index).unwrap()
    }

    /// Obtains or create the metatable of the table.
    pub fn get_or_create_metatable(mut self) -> LuaTable<PushGuard<L>> {
        let result = unsafe { ffi::lua_getmetatable(self.table.as_mut_lua().0, -1) };

        if result == 0 {
            unsafe {
                ffi::lua_newtable(self.table.as_mut_lua().0);
                ffi::lua_setmetatable(self.table.as_mut_lua().0, -2);
                let r = ffi::lua_getmetatable(self.table.as_mut_lua().0, -1);
                assert!(r != 0);
            }
        }

        LuaTable {
            table: PushGuard { lua: self.table, size: 1 }
        }
    }
}

impl<'t, L, K, V> Iterator for LuaTableIterator<'t, L, K, V>
                  where L: AsMutLua + 't,
                        K: for<'i, 'j> LuaRead<&'i mut &'j mut LuaTableIterator<'t, L, K, V>> + 'static,
                        V: for<'i, 'j> LuaRead<&'i mut &'j mut LuaTableIterator<'t, L, K, V>> + 'static
{
    type Item = Option<(K, V)>;

    fn next(&mut self) -> Option<Option<(K,V)>> {
        if self.finished {
            return None;
        }

        // this call pushes the next key and value on the stack
        if unsafe { ffi::lua_next(self.table.as_mut_lua().0, -2) } == 0 {
            self.finished = true;
            return None;
        }

        let mut me = self;
        let key = LuaRead::lua_read_at_position(&mut me, -2).ok();
        let value = LuaRead::lua_read_at_position(&mut me, -1).ok();

        // removing the value, leaving only the key on the top of the stack
        unsafe { ffi::lua_pop(me.table.as_mut_lua().0, 1) };

        //
        if key.is_none() || value.is_none() {
            Some(None)
        } else {
            Some(Some((key.unwrap(), value.unwrap())))
        }
    }
}

impl<'t, L, K, V> Drop for LuaTableIterator<'t, L, K, V> where L: AsMutLua + 't {
    fn drop(&mut self) {
        if !self.finished {
            unsafe { ffi::lua_pop(self.table.table.as_mut_lua().0, 1) }
        }
    }
}
<|endoftext|>


<commit_before>// Workbook.
struct File_Protection;
struct Code_Page;
struct DSF;
struct Tab_ID;
struct FnGroupCount;
struct WorkbookProtection;

struct Window {
    horizontal_pos: u16,
    vertical_pos: u16,
    width_: u16,
    height_: u16,
    options_: u16,
    active_worksheet_index_: u16,
    first_viisble_tab_index_: u16,
    selected_worksheet_no_: u16,
    worksheet_tabbar_width_: u16,
}

impl Window {
    pub fn new() -> Window {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }
}

struct Backup;
struct Hide_Obj;
struct Date_Mode;
struct Precision;
struct Refresh_All;
struct Book_Bool;

struct Font {
    height_: u16,
    options_: u16,
    color_index: u16, // Colo*U*r people just need to deal. :]
    weight_: u16,
    escapement_type: u16,
    underline_type: u8,
    family_: u8,
    character_set_: u8,
    unused_: u8,
    name_: String,
}

impl Font {
    pub fn new() -> Font {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

struct Format {
    index_: u16,
    fmtstring_: String,
}

impl Format {

    pub fn new() -> Format {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

struct XF {
    font_record_index_: u16,
    format_record_index_: u16,
    protection_type_: u16,
    alignment_: u8,
    rotation_: u8,
    text_properties_: u8,
    used_attributes_: u8,
    border_lines_: u32,
    color1_: u32,
    color2_: u16,
}

impl XF {
    pub fn new() -> XF {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }
}

struct Style {
    xf_record_index_: u16,
    identifier_: u8,
    level_: u8,
    name_: String,
}

impl Style {
    pub fn new() -> Style {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

struct Palette;
struct Use_Selfs;

struct Bound_Sheet {
    bof_pos_: u32,
    visibility_: u8,
    type_: u8,
    name_: String,
}

impl Bound_Sheet {
    pub fn new() -> Bound_Sheet {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

struct Country;
struct Link_Table;

struct Shared_String_Table {
    strings_total_: u32,
    unique_strings_Total_: u32,
    strings_: Vec<String>,
}

impl Shared_String_Table {
    pub fn new() -> Shared_String_Table {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

struct Ext_SST {
    strings_total_: u16,
    stream_pos_: Vec<u32>,
    first_string_pos_: Vec<u16>,
    unused_: Vec<u16>,
}

impl Ext_SST {
    pub fn new() -> Ext_SST {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

pub struct Workbook {
    bof_: BOF,
    window_: Window,
    fonts_: Vec<Font>,
    xfs_: Vec<XF>,
    styles_: Vec<Style>,
    formats_: Vec<Format>,
    bound_sheets_: Vec<Bound_Sheet>,
    sst_: Shared_String_Table,
    eof_: YEOF,
}

pub impl Workbook {
    pub fn new() -> Workbook {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}<commit_msg>Thing<commit_after>// Workbook.
struct File_Protection;
struct Code_Page;
struct DSF;
struct Tab_ID;
struct FnGroupCount;
struct WorkbookProtection;

struct Window {
    horizontal_pos: u16,
    vertical_pos: u16,
    width_: u16,
    height_: u16,
    options_: u16,
    active_worksheet_index_: u16,
    first_viisble_tab_index_: u16,
    selected_worksheet_no_: u16,
    worksheet_tabbar_width_: u16,
}

impl Window {
    pub fn new() -> Window {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }
}

struct Backup;
struct Hide_Obj;
struct Date_Mode;
struct Precision;
struct Refresh_All;
struct Book_Bool;

struct Font {
    height_: u16,
    options_: u16,
    color_index: u16, // Colo*U*r people just need to deal. :]
    weight_: u16,
    escapement_type: u16,
    underline_type: u8,
    family_: u8,
    character_set_: u8,
    unused_: u8,
    name_: String,
}

impl Font {
    pub fn new() -> Font {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

struct Format {
    index_: u16,
    fmtstring_: String,
}

impl Format {

    pub fn new() -> Format {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

struct XF {
    font_record_index_: u16,
    format_record_index_: u16,
    protection_type_: u16,
    alignment_: u8,
    rotation_: u8,
    text_properties_: u8,
    used_attributes_: u8,
    border_lines_: u32,
    color1_: u32,
    color2_: u16,
}

impl XF {
    pub fn new() -> XF {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }
}

struct Style {
    xf_record_index_: u16,
    identifier_: u8,
    level_: u8,
    name_: String,
}

impl Style {
    pub fn new() -> Style {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

struct Palette;
struct Use_Selfs;

struct Bound_Sheet {
    bof_pos_: u32,
    visibility_: u8,
    type_: u8,
    name_: String,
}

impl Bound_Sheet {
    pub fn new() -> Bound_Sheet {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

struct Country;
struct Link_Table;

struct Shared_String_Table {
    strings_total_: u32,
    unique_strings_Total_: u32,
    strings_: Vec<String>,
}

impl Shared_String_Table {
    pub fn new() -> Shared_String_Table {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}

struct Ext_SST {
    strings_total_: u16,
    stream_pos_: Vec<u32>,
    first_string_pos_: Vec<u16>,
    unused_: Vec<u16>,
}

impl Ext_SST {
    pub fn new() -> Ext_SST {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!(); //Thing
    }
}

pub struct Workbook {
    bof_: BOF,
    window_: Window,
    fonts_: Vec<Font>,
    xfs_: Vec<XF>,
    styles_: Vec<Style>,
    formats_: Vec<Format>,
    bound_sheets_: Vec<Bound_Sheet>,
    sst_: Shared_String_Table,
    eof_: YEOF,
}

pub impl Workbook {
    pub fn new() -> Workbook {
        unimplemented!();
    }

    pub fn Read() {
        unimplemented!();
    }

    pub fn Write() {
        unimplemented!();
    }

    pub fn Data_Size() -> u32 {
        unimplemented!();
    }

    pub fn Record_Size() -> u32 {
        unimplemented!();
    }
}<|endoftext|>


<commit_before>use std;

fn f() {
}

import std::net;    //~ ERROR view items must be declared at the top

fn main() {
}

<commit_msg>xfail view-items-at-top<commit_after>// xfail-test

use std;

fn f() {
}

import std::net;    //~ ERROR view items must be declared at the top

fn main() {
}

<|endoftext|>