<commit_before>use expectest::prelude::*;
use expectest::expect;
use super::{FilterInfo, filter_interaction, filter_consumers, execute_state_change, ProviderInfo};
use pact_matching::models::*;
use pact_matching::models::provider_states::*;
use pact_matching::s;
use pact_consumer::prelude::*;
use pact_consumer::*;
use env_logger::*;
use crate::PactSource;
use std::panic::catch_unwind;
use crate::pact_broker::Link;
use maplit::*;
use serde_json::json;

#[test]
fn if_no_interaction_filter_is_defined_returns_true() {
  let interaction = Interaction::default();
  expect!(filter_interaction(&interaction, &FilterInfo::None)).to(be_true());
}

#[test]
fn if_an_interaction_filter_is_defined_returns_false_if_the_description_does_not_match() {
  let interaction = Interaction { description: s!("bob"), .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::Description(s!("fred")))).to(be_false());
}

#[test]
fn if_an_interaction_filter_is_defined_returns_true_if_the_description_does_match() {
  let interaction = Interaction { description: s!("bob"), .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::Description(s!("bob")))).to(be_true());
}

#[test]
fn uses_regexs_to_match_the_description() {
  let interaction = Interaction { description: s!("bobby"), .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::Description(s!("bob.*")))).to(be_true());
}

#[test]
fn if_an_interaction_state_filter_is_defined_returns_false_if_the_state_does_not_match() {
  let interaction = Interaction { provider_states: vec![ ProviderState::default(&s!("bob")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::State(s!("fred")))).to(be_false());
}

#[test]
fn if_an_interaction_state_filter_is_defined_returns_true_if_the_state_does_match() {
  let interaction = Interaction { provider_states: vec![ ProviderState::default(&s!("bob")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::State(s!("bob")))).to(be_true());
}

#[test]
fn uses_regexs_to_match_the_state() {
  let interaction = Interaction { provider_states: vec![ ProviderState::default(&s!("bobby")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::State(s!("bob.*")))).to(be_true());
}

#[test]
fn if_the_state_filter_is_empty_returns_false_if_the_interaction_state_is_defined() {
  let interaction = Interaction { provider_states: vec![ ProviderState::default(&s!("bobby")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::State(s!("")))).to(be_false());
}

#[test]
fn if_the_state_filter_is_empty_returns_true_if_the_interaction_state_is_not_defined() {
  let interaction = Interaction { provider_states: vec![], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::State(s!("")))).to(be_true());
}

#[test]
fn if_the_state_filter_and_interaction_filter_is_defined_must_match_both() {
  let interaction = Interaction { description: s!("freddy"), provider_states: vec![ ProviderState::default(&s!("bobby")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::DescriptionAndState(s!(".*ddy"), s!("bob.*")))).to(be_true());
}

#[test]
fn if_the_state_filter_and_interaction_filter_is_defined_is_false_if_the_provider_state_does_not_match() {
  let interaction = Interaction { description: s!("freddy"), provider_states: vec![ ProviderState::default(&s!("boddy")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::DescriptionAndState(s!(".*ddy"), s!("bob.*")))).to(be_false());
}

#[test]
fn if_the_state_filter_and_interaction_filter_is_defined_is_false_if_the_description_does_not_match() {
  let interaction = Interaction { description: s!("frebby"), provider_states: vec![ ProviderState::default(&s!("bobby")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::DescriptionAndState(s!(".*ddy"), s!("bob.*")))).to(be_false());
}

#[test]
fn if_the_state_filter_and_interaction_filter_is_defined_is_false_if_both_do_not_match() {
  let interaction = Interaction { description: s!("joe"), provider_states: vec![ ProviderState::default(&s!("author")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::DescriptionAndState(s!(".*ddy"), s!("bob.*")))).to(be_false());
}

#[test]
fn if_no_consumer_filter_is_defined_returns_true() {
  let consumers = vec![];
  let result = Err(s!(""));
  expect!(filter_consumers(&consumers, &result)).to(be_true());
}

#[test]
fn if_a_consumer_filter_is_defined_returns_false_if_the_consumer_name_does_not_match() {
  let consumers = vec![s!("fred"), s!("joe")];
  let result = Ok((Pact { consumer: Consumer { name: s!("bob") }, .. Pact::default() }, PactSource::Unknown));
  expect!(filter_consumers(&consumers, &result)).to(be_false());
}

#[test]
fn if_a_consumer_filter_is_defined_returns_true_if_the_result_is_an_error() {
  let consumers = vec![s!("fred"), s!("joe")];
  let result = Err(s!(""));
  expect!(filter_consumers(&consumers, &result)).to(be_true());
}

#[test]
fn if_a_consumer_filter_is_defined_returns_true_if_the_consumer_name_does_match() {
  let consumers = vec![s!("fred"), s!("joe"), s!("bob")];
  let result = Ok((Pact { consumer: Consumer { name: s!("bob") }, .. Pact::default() }, PactSource::Unknown));
  expect!(filter_consumers(&consumers, &result)).to(be_true());
}

#[tokio::test]
async fn test_state_change_with_parameters() {
  init().unwrap_or(());

  let server = PactBuilder::new("RustPactVerifier", "SomeRunningProvider")
    .interaction("a state change request", |i| {
      i.request.method("POST");
      i.request.path("/");
      i.request.header("Content-Type", "application/json");
      i.request.body("{\"A\":\"1\",\"B\":\"2\",\"action\":\"setup\",\"state\":\"TestState\"}");
      i.response.status(200);
    })
    .start_mock_server();

  let provider_state = ProviderState {
    name: s!("TestState"),
    params: hashmap!{
        s!("A") => json!("1"),
        s!("B") => json!("2")
      }
  };

  let provider = ProviderInfo { state_change_url: Some(server.url().to_string()), .. ProviderInfo::default() };
  let result = execute_state_change(&provider_state, &provider, true, None).await;
  expect!(result.clone()).to(be_ok());
}

#[tokio::test]
async fn test_state_change_with_parameters_in_query() {
  init().unwrap_or(());

  let server = PactBuilder::new("RustPactVerifier", "SomeRunningProvider")
    .interaction("a state change request with params in the query string", |i| {
      i.request.method("POST");
      i.request.path("/");
      i.request.query_param("state", "TestState");
      i.request.query_param("action", "setup");
      i.request.query_param("A", "1");
      i.request.query_param("B", "2");
      i.response.status(200);
    })
    .start_mock_server();

  let provider_state = ProviderState {
    name: s!("TestState"),
    params: hashmap!{
        s!("A") => json!("1"),
        s!("B") => json!("2")
      }
  };

  let provider = ProviderInfo { state_change_url: Some(server.url().to_string()),
    state_change_body: false, .. ProviderInfo::default() };
  let result = execute_state_change(&provider_state, &provider, true, None).await;
  expect!(result.clone()).to(be_ok());
}

#[test]
fn publish_result_does_nothing_if_not_from_broker() {
  init().unwrap_or(());

  let server_response = catch_unwind(|| {
    let mut runtime = tokio::runtime::Builder::new()
      .basic_scheduler()
      .enable_all()
      .build()
      .unwrap();

    runtime.block_on(async {
      PactBuilder::new("RustPactVerifier", "PactBroker")
        .interaction("publish results", |i| {
          i.request.method("POST");
          i.request.path("/");
          i.response.status(201);
        })
        .spawn_mock_server()
        .await;

      let options = super::VerificationOptions {
        publish: true,
        provider_version: None,
        build_url: None
      };
      super::publish_result(&vec![], &PactSource::File("/tmp/test".into()), &options).await;
    })
  });
  expect!(server_response).to(be_err());
}

#[tokio::test]
async fn publish_successful_result_to_broker() {
  init().unwrap_or(());

  let server = PactBuilder::new("RustPactVerifier", "PactBroker")
    .interaction("publish results", |i| {
      i.request.method("POST");
      i.request.path("/path/to/pact/verification");
      i.request.json_body(json_pattern!({
        "providerApplicationVersion": "1",
        "success": true
      }));
      i.response.status(201);
    })
    .start_mock_server();

  let options = super::VerificationOptions {
    publish: true,
    provider_version: Some("1".into()),
    build_url: None
  };
  let links = vec![
    Link {
      name: "pb:publish-verification-results".to_string(),
      href: Some(server.path("/path/to/pact/verification".to_string()).to_string()),
      templated: false
    }
  ];
  let source = PactSource::BrokerUrl("Test".to_string(), server.url().to_string(), None, links);
  super::publish_result(&vec![], &source, &options).await;
}
<commit_msg>pact_verifier tests: Change to spawned mock server<commit_after>use expectest::prelude::*;
use expectest::expect;
use super::{FilterInfo, filter_interaction, filter_consumers, execute_state_change, ProviderInfo};
use pact_matching::models::*;
use pact_matching::models::provider_states::*;
use pact_matching::s;
use pact_consumer::prelude::*;
use pact_consumer::*;
use env_logger::*;
use crate::PactSource;
use std::panic::catch_unwind;
use crate::pact_broker::Link;
use maplit::*;
use serde_json::json;

#[test]
fn if_no_interaction_filter_is_defined_returns_true() {
  let interaction = Interaction::default();
  expect!(filter_interaction(&interaction, &FilterInfo::None)).to(be_true());
}

#[test]
fn if_an_interaction_filter_is_defined_returns_false_if_the_description_does_not_match() {
  let interaction = Interaction { description: s!("bob"), .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::Description(s!("fred")))).to(be_false());
}

#[test]
fn if_an_interaction_filter_is_defined_returns_true_if_the_description_does_match() {
  let interaction = Interaction { description: s!("bob"), .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::Description(s!("bob")))).to(be_true());
}

#[test]
fn uses_regexs_to_match_the_description() {
  let interaction = Interaction { description: s!("bobby"), .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::Description(s!("bob.*")))).to(be_true());
}

#[test]
fn if_an_interaction_state_filter_is_defined_returns_false_if_the_state_does_not_match() {
  let interaction = Interaction { provider_states: vec![ ProviderState::default(&s!("bob")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::State(s!("fred")))).to(be_false());
}

#[test]
fn if_an_interaction_state_filter_is_defined_returns_true_if_the_state_does_match() {
  let interaction = Interaction { provider_states: vec![ ProviderState::default(&s!("bob")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::State(s!("bob")))).to(be_true());
}

#[test]
fn uses_regexs_to_match_the_state() {
  let interaction = Interaction { provider_states: vec![ ProviderState::default(&s!("bobby")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::State(s!("bob.*")))).to(be_true());
}

#[test]
fn if_the_state_filter_is_empty_returns_false_if_the_interaction_state_is_defined() {
  let interaction = Interaction { provider_states: vec![ ProviderState::default(&s!("bobby")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::State(s!("")))).to(be_false());
}

#[test]
fn if_the_state_filter_is_empty_returns_true_if_the_interaction_state_is_not_defined() {
  let interaction = Interaction { provider_states: vec![], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::State(s!("")))).to(be_true());
}

#[test]
fn if_the_state_filter_and_interaction_filter_is_defined_must_match_both() {
  let interaction = Interaction { description: s!("freddy"), provider_states: vec![ ProviderState::default(&s!("bobby")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::DescriptionAndState(s!(".*ddy"), s!("bob.*")))).to(be_true());
}

#[test]
fn if_the_state_filter_and_interaction_filter_is_defined_is_false_if_the_provider_state_does_not_match() {
  let interaction = Interaction { description: s!("freddy"), provider_states: vec![ ProviderState::default(&s!("boddy")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::DescriptionAndState(s!(".*ddy"), s!("bob.*")))).to(be_false());
}

#[test]
fn if_the_state_filter_and_interaction_filter_is_defined_is_false_if_the_description_does_not_match() {
  let interaction = Interaction { description: s!("frebby"), provider_states: vec![ ProviderState::default(&s!("bobby")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::DescriptionAndState(s!(".*ddy"), s!("bob.*")))).to(be_false());
}

#[test]
fn if_the_state_filter_and_interaction_filter_is_defined_is_false_if_both_do_not_match() {
  let interaction = Interaction { description: s!("joe"), provider_states: vec![ ProviderState::default(&s!("author")) ], .. Interaction::default() };
  expect!(filter_interaction(&interaction, &FilterInfo::DescriptionAndState(s!(".*ddy"), s!("bob.*")))).to(be_false());
}

#[test]
fn if_no_consumer_filter_is_defined_returns_true() {
  let consumers = vec![];
  let result = Err(s!(""));
  expect!(filter_consumers(&consumers, &result)).to(be_true());
}

#[test]
fn if_a_consumer_filter_is_defined_returns_false_if_the_consumer_name_does_not_match() {
  let consumers = vec![s!("fred"), s!("joe")];
  let result = Ok((Pact { consumer: Consumer { name: s!("bob") }, .. Pact::default() }, PactSource::Unknown));
  expect!(filter_consumers(&consumers, &result)).to(be_false());
}

#[test]
fn if_a_consumer_filter_is_defined_returns_true_if_the_result_is_an_error() {
  let consumers = vec![s!("fred"), s!("joe")];
  let result = Err(s!(""));
  expect!(filter_consumers(&consumers, &result)).to(be_true());
}

#[test]
fn if_a_consumer_filter_is_defined_returns_true_if_the_consumer_name_does_match() {
  let consumers = vec![s!("fred"), s!("joe"), s!("bob")];
  let result = Ok((Pact { consumer: Consumer { name: s!("bob") }, .. Pact::default() }, PactSource::Unknown));
  expect!(filter_consumers(&consumers, &result)).to(be_true());
}

#[tokio::test]
async fn test_state_change_with_parameters() {
  init().unwrap_or(());

  let server = PactBuilder::new("RustPactVerifier", "SomeRunningProvider")
    .interaction("a state change request", |i| {
      i.request.method("POST");
      i.request.path("/");
      i.request.header("Content-Type", "application/json");
      i.request.body("{\"A\":\"1\",\"B\":\"2\",\"action\":\"setup\",\"state\":\"TestState\"}");
      i.response.status(200);
    })
    .spawn_mock_server()
    .await;

  let provider_state = ProviderState {
    name: s!("TestState"),
    params: hashmap!{
        s!("A") => json!("1"),
        s!("B") => json!("2")
      }
  };

  let provider = ProviderInfo { state_change_url: Some(server.url().to_string()), .. ProviderInfo::default() };
  let result = execute_state_change(&provider_state, &provider, true, None).await;
  expect!(result.clone()).to(be_ok());
}

#[tokio::test]
async fn test_state_change_with_parameters_in_query() {
  init().unwrap_or(());

  let server = PactBuilder::new("RustPactVerifier", "SomeRunningProvider")
    .interaction("a state change request with params in the query string", |i| {
      i.request.method("POST");
      i.request.path("/");
      i.request.query_param("state", "TestState");
      i.request.query_param("action", "setup");
      i.request.query_param("A", "1");
      i.request.query_param("B", "2");
      i.response.status(200);
    })
    .spawn_mock_server()
    .await;

  let provider_state = ProviderState {
    name: s!("TestState"),
    params: hashmap!{
        s!("A") => json!("1"),
        s!("B") => json!("2")
      }
  };

  let provider = ProviderInfo { state_change_url: Some(server.url().to_string()),
    state_change_body: false, .. ProviderInfo::default() };
  let result = execute_state_change(&provider_state, &provider, true, None).await;
  expect!(result.clone()).to(be_ok());
}

#[test]
fn publish_result_does_nothing_if_not_from_broker() {
  init().unwrap_or(());

  let server_response = catch_unwind(|| {
    let mut runtime = tokio::runtime::Builder::new()
      .basic_scheduler()
      .enable_all()
      .build()
      .unwrap();

    runtime.block_on(async {
      PactBuilder::new("RustPactVerifier", "PactBroker")
        .interaction("publish results", |i| {
          i.request.method("POST");
          i.request.path("/");
          i.response.status(201);
        })
        .spawn_mock_server()
        .await;

      let options = super::VerificationOptions {
        publish: true,
        provider_version: None,
        build_url: None
      };
      super::publish_result(&vec![], &PactSource::File("/tmp/test".into()), &options).await;
    })
  });
  expect!(server_response).to(be_err());
}

#[tokio::test]
async fn publish_successful_result_to_broker() {
  init().unwrap_or(());

  let server = PactBuilder::new("RustPactVerifier", "PactBroker")
    .interaction("publish results", |i| {
      i.request.method("POST");
      i.request.path("/path/to/pact/verification");
      i.request.json_body(json_pattern!({
        "providerApplicationVersion": "1",
        "success": true
      }));
      i.response.status(201);
    })
    .spawn_mock_server()
    .await;

  let options = super::VerificationOptions {
    publish: true,
    provider_version: Some("1".into()),
    build_url: None
  };
  let links = vec![
    Link {
      name: "pb:publish-verification-results".to_string(),
      href: Some(server.path("/path/to/pact/verification".to_string()).to_string()),
      templated: false
    }
  ];
  let source = PactSource::BrokerUrl("Test".to_string(), server.url().to_string(), None, links);
  super::publish_result(&vec![], &source, &options).await;
}
<|endoftext|>


<commit_before>struct Foo<'a> {
    x: &'a i32,
}

fn main() {
    let _y=5;
    let x;                    // -+ x goes into scope
                              //  |
    {                         //  |
        let y = &_y;           // ---+ y goes into scope
        let f = Foo { x: y }; // ---+ f goes into scope
        x = f.x;             //  | | error here
    }                         // ---+ f and y go out of scope
                              //  |
    println!("{}", x);        //  |
}                             // -+ x goes out of scope

<commit_msg>lol tsk tsk<commit_after>struct Foo<'a> {
    x: &'a i32,
}

fn main() {
    let _y=5;
    let x;                    // -+ x goes into scope
                              //  |
    {                         //  |
        let y = &_y;           // ---+ y goes into scope
        let f = Foo { x: y }; // ---+ f goes into scope
        x = *&f.x;             //  | | error here
    }                         // ---+ f and y go out of scope
                              //  |
    println!("{}", x);        //  |
}                             // -+ x goes out of scope

<|endoftext|>


<commit_before>// Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
// All rights reserved. This file is part of rpf, distributed under the
// BSD 3-Clause license. For full terms please see the LICENSE file.

use std::path::{PathBuf,Path};
use std::fs::{PathExt};

/// Adds some useful functions for manipulating and retrieving information from
/// paths
pub trait PathMod {
    /// Returns a `PathBuf` of `&self`'s last component
    ///
    /// # Example
    ///
    /// ```
    /// use rpf::PathMod;
    /// use std::path::Path;
    ///
    /// let path = Path::new("/tmp/test/mod");
    /// let last = path.last_component();
    /// ```
    fn last_component(&self) -> PathBuf;

    /// Returns a `PathBuf` of `&self`'s first component
    ///
    /// # Example
    /// ```
    /// use rpf::PathMod;
    /// use std::path::PathBuf;
    ///
    /// let path = PathBuf::from("/tmp/test/mod");
    /// let first = path.first_component();
    /// assert_eq!(first, PathBuf::from("/"));
    /// ```
    fn first_component(&self) -> PathBuf;

    /// Returns a `PathBuf` of `&self` relative from `rel_from`
    ///
    /// # Example
    /// ```
    /// use rpf::PathMod;
    /// use std::path::PathBuf;
    ///
    /// let path = PathBuf::from("mod");
    /// let parent = PathBuf::from("/tmp/test/mod");
    /// let rel = path.rel_to(&parent);
    /// ```
    fn rel_to<T: AsRef<Path>>(&self, rel_from: &T) -> PathBuf;

    /// Returns a `&str` for a path, returns a blank string if unable to
    /// get a string for the path
    ///
    /// # Example
    /// ```
    /// use rpf::PathMod;
    /// use std::path::PathBuf;
    ///
    /// let path = PathBuf::from("/usr/share");
    /// let path_str = &path.as_str();
    /// assert_eq!(path_str, &"/usr/share");
    /// ```
    fn as_str(&self) -> &str;

    /// Returns a `String` for a path, returns an empty string if unable to get
    /// a string for a path
    ///
    /// # Example
    /// ```
    /// use rpf::PathMod;
    /// use std::path::PathBuf;
    ///
    /// let path_string = PathBuf::from("/var/log/test").as_string();
    /// assert_eq!(path_string, "/var/log/test".to_string());
    /// ```
    fn as_string(&self) -> String;
}

impl PathMod for PathBuf {
    fn last_component(&self) -> PathBuf {
        match self.components().last() {
            Some(s) => { PathBuf::from(s.as_os_str()) },
            None => { PathBuf::new() },
        }
    }

    fn first_component(&self) -> PathBuf {
        match self.components().nth(0) {
            Some(s) => { PathBuf::from(s.as_os_str()) },
            None => { PathBuf::new() },
        }
    }

    fn rel_to<T: AsRef<Path>>(&self, rel_from: &T) -> PathBuf {
        self.relative_from(&rel_from).unwrap_or(&PathBuf::new()).to_path_buf()
    }

    fn as_str(&self) -> &str {
        match self.to_str() {
            Some(s) => { s },
            None => { "" },
        }
    }

    fn as_string(&self) -> String {
        self.as_str().to_string()
    }
}

impl PathMod for Path {
    fn last_component(&self) -> PathBuf {
        match self.components().last() {
            Some(s) => { PathBuf::from(s.as_os_str()) },
            None => { PathBuf::new() },
        }
    }

    fn first_component(&self) -> PathBuf {
        match self.components().nth(0) {
            Some(s) => { PathBuf::from(s.as_os_str()) },
            None => { PathBuf::new() },
        }
    }

    fn rel_to<T: AsRef<Path>>(&self, rel_from: &T) -> PathBuf {
        self.relative_from(&rel_from).unwrap_or(&PathBuf::new()).to_path_buf()
    }

    fn as_str(&self) -> &str {
        match self.to_str() {
            Some(s) => { s },
            None => { "" },
        }
    }

    fn as_string(&self) -> String {
        self.as_str().to_string()
    }
}

#[test]
fn test_pathmod_first_comp() {
    let comp = Path::new("/etc/test").first_component();
    assert_eq!(comp, PathBuf::from("/"));
}

#[test]
fn test_pathmod_last_comp() {
    let comp = Path::new("/etc/test").last_component();
    assert_eq!(comp, PathBuf::from("test"));
}

#[test]
fn test_pathmod_as_str() {
    let string = Path::new("/var/log/test").as_str();
    assert_eq!(string, "/var/log/test");
}

#[test]
fn test_pathmod_as_string() {
    let string = Path::new("/var/log/test").as_string();
    assert_eq!(string, "/var/log/test".to_string());
}
<commit_msg>pathmod: remove unneeded `use`<commit_after>// Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
// All rights reserved. This file is part of rpf, distributed under the
// BSD 3-Clause license. For full terms please see the LICENSE file.

use std::path::{PathBuf,Path};

/// Adds some useful functions for manipulating and retrieving information from
/// paths
pub trait PathMod {
    /// Returns a `PathBuf` of `&self`'s last component
    ///
    /// # Example
    ///
    /// ```
    /// use rpf::PathMod;
    /// use std::path::Path;
    ///
    /// let path = Path::new("/tmp/test/mod");
    /// let last = path.last_component();
    /// ```
    fn last_component(&self) -> PathBuf;

    /// Returns a `PathBuf` of `&self`'s first component
    ///
    /// # Example
    /// ```
    /// use rpf::PathMod;
    /// use std::path::PathBuf;
    ///
    /// let path = PathBuf::from("/tmp/test/mod");
    /// let first = path.first_component();
    /// assert_eq!(first, PathBuf::from("/"));
    /// ```
    fn first_component(&self) -> PathBuf;

    /// Returns a `PathBuf` of `&self` relative from `rel_from`
    ///
    /// # Example
    /// ```
    /// use rpf::PathMod;
    /// use std::path::PathBuf;
    ///
    /// let path = PathBuf::from("mod");
    /// let parent = PathBuf::from("/tmp/test/mod");
    /// let rel = path.rel_to(&parent);
    /// ```
    fn rel_to<T: AsRef<Path>>(&self, rel_from: &T) -> PathBuf;

    /// Returns a `&str` for a path, returns a blank string if unable to
    /// get a string for the path
    ///
    /// # Example
    /// ```
    /// use rpf::PathMod;
    /// use std::path::PathBuf;
    ///
    /// let path = PathBuf::from("/usr/share");
    /// let path_str = &path.as_str();
    /// assert_eq!(path_str, &"/usr/share");
    /// ```
    fn as_str(&self) -> &str;

    /// Returns a `String` for a path, returns an empty string if unable to get
    /// a string for a path
    ///
    /// # Example
    /// ```
    /// use rpf::PathMod;
    /// use std::path::PathBuf;
    ///
    /// let path_string = PathBuf::from("/var/log/test").as_string();
    /// assert_eq!(path_string, "/var/log/test".to_string());
    /// ```
    fn as_string(&self) -> String;
}

impl PathMod for PathBuf {
    fn last_component(&self) -> PathBuf {
        match self.components().last() {
            Some(s) => { PathBuf::from(s.as_os_str()) },
            None => { PathBuf::new() },
        }
    }

    fn first_component(&self) -> PathBuf {
        match self.components().nth(0) {
            Some(s) => { PathBuf::from(s.as_os_str()) },
            None => { PathBuf::new() },
        }
    }

    fn rel_to<T: AsRef<Path>>(&self, rel_from: &T) -> PathBuf {
        self.relative_from(&rel_from).unwrap_or(&PathBuf::new()).to_path_buf()
    }

    fn as_str(&self) -> &str {
        match self.to_str() {
            Some(s) => { s },
            None => { "" },
        }
    }

    fn as_string(&self) -> String {
        self.as_str().to_string()
    }
}

impl PathMod for Path {
    fn last_component(&self) -> PathBuf {
        match self.components().last() {
            Some(s) => { PathBuf::from(s.as_os_str()) },
            None => { PathBuf::new() },
        }
    }

    fn first_component(&self) -> PathBuf {
        match self.components().nth(0) {
            Some(s) => { PathBuf::from(s.as_os_str()) },
            None => { PathBuf::new() },
        }
    }

    fn rel_to<T: AsRef<Path>>(&self, rel_from: &T) -> PathBuf {
        self.relative_from(&rel_from).unwrap_or(&PathBuf::new()).to_path_buf()
    }

    fn as_str(&self) -> &str {
        match self.to_str() {
            Some(s) => { s },
            None => { "" },
        }
    }

    fn as_string(&self) -> String {
        self.as_str().to_string()
    }
}

#[test]
fn test_pathmod_first_comp() {
    let comp = Path::new("/etc/test").first_component();
    assert_eq!(comp, PathBuf::from("/"));
}

#[test]
fn test_pathmod_last_comp() {
    let comp = Path::new("/etc/test").last_component();
    assert_eq!(comp, PathBuf::from("test"));
}

#[test]
fn test_pathmod_as_str() {
    let string = Path::new("/var/log/test").as_str();
    assert_eq!(string, "/var/log/test");
}

#[test]
fn test_pathmod_as_string() {
    let string = Path::new("/var/log/test").as_string();
    assert_eq!(string, "/var/log/test".to_string());
}
<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use gl_context::{GLContext, GLContextExistence};
use shader::*;
use std::cell::RefCell;
use std::ffi::CString;
use std::marker::ContravariantLifetime;
use std::mem;
use std::num;
use std::ptr;
use std::rc::Rc;

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case)]
pub fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  let c_str = CString::from_slice(name.as_bytes());
  let ptr = c_str.as_ptr() as *const i8;
  unsafe {
    gl::GetAttribLocation(shader_program, ptr)
  }
}

pub struct BufferHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> BufferHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> BufferHandle<'a> {
    let mut gl_id = 0;

    unsafe {
      gl::GenBuffers(1, &mut gl_id);
    }

    assert!(gl_id != 0);

    BufferHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for BufferHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.gl_id);
    }
  }
}

/// Fixed-size VRAM buffer for individual bytes.
pub struct GLByteBuffer<'a> {
  pub handle: BufferHandle<'a>,
  /// number of bytes in the buffer.
  pub length: usize,
  /// maximum number of bytes in the buffer.
  pub capacity: usize,
}

impl<'a> GLByteBuffer<'a> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: usize,
  ) -> GLByteBuffer<'a> {
    let handle = BufferHandle::new(gl);

    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, handle.gl_id);

      gl::BufferData(
        gl::ARRAY_BUFFER,
        capacity as GLsizeiptr,
        ptr::null(),
        gl::DYNAMIC_DRAW,
      );
    }

    match gl_context.get_error() {
      gl::NO_ERROR => {},
      gl::OUT_OF_MEMORY => panic!("Out of VRAM"),
      err => warn!("OpenGL error 0x{:x}", err),
    }

    GLByteBuffer {
      handle: handle,
      length: 0,
      capacity: capacity,
    }
  }

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);
    }
  }

  /// Add more data into this buffer.
  pub unsafe fn push(&mut self, gl: &mut GLContext, vs: *const u8, count: usize) {
    assert!(
      self.length + count <= self.capacity,
      "GLByteBuffer::push {} into a {}/{} full GLByteBuffer",
      count,
      self.length,
      self.capacity
    );

    self.update_inner(gl, self.length, vs, count);
    self.length += count;
  }

  pub fn swap_remove(&mut self, _gl: &mut GLContext, i: usize, count: usize) {
    assert!(count <= self.length);
    self.length -= count;
    assert!(i <= self.length);

    // In the `i == self.length` case, we don't bother with the swap;
    // decreasing `self.length` is enough.

    if i < self.length {
      assert!(
        i <= self.length - count,
        "GLByteBuffer::swap_remove would cause copy in overlapping regions"
      );

      unsafe {
        gl::CopyBufferSubData(
          gl::ARRAY_BUFFER,
          gl::ARRAY_BUFFER,
          self.length as i64,
          i as i64,
          count as i64,
        );
      }
    }
  }

  pub unsafe fn update(&self, gl: &mut GLContext, idx: usize, vs: *const u8, count: usize) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

  unsafe fn update_inner(
    &self,
    _gl: &mut GLContext,
    idx: usize,
    vs: *const u8,
    count: usize,
  ) {
    assert!(idx + count <= self.capacity);

    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      idx as i64,
      count as i64,
      mem::transmute(vs)
    );
  }
}

/// Fixed-size typed VRAM buffer, optimized for bulk inserts.
pub struct GLBuffer<'a, T> {
  pub byte_buffer: GLByteBuffer<'a>,
}

impl<'a, T> GLBuffer<'a, T> {
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: usize,
  ) -> GLBuffer<'a, T> {
    GLBuffer {
      byte_buffer: GLByteBuffer::new(gl, gl_context, capacity * mem::size_of::<T>()),
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    unsafe {
      self.byte_buffer.push(
        gl,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len()
      );
    }
  }

  pub fn update(&mut self, gl: &mut GLContext, idx: usize, vs: &[T]) {
    unsafe {
      self.byte_buffer.update(
        gl,
        mem::size_of::<T>() * idx,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len(),
      );
    }
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.byte_buffer.swap_remove(
      gl,
      mem::size_of::<T>() * idx,
      mem::size_of::<T>() * count,
    );
  }
}

#[derive(Show)]
#[derive(Copy, Clone)]
pub enum DrawMode {
  Lines,
  Triangles,
  Points,
}

impl DrawMode {
  fn to_enum(&self) -> GLenum {
    match *self {
      DrawMode::Lines     => gl::LINES,
      DrawMode::Triangles => gl::TRIANGLES,
      DrawMode::Points    => gl::POINTS,
    }
  }
}

#[derive(Show)]
#[derive(Copy, Clone)]
pub enum GLType {
  Float,
  UInt,
  Int,
}

impl GLType {
  pub fn size(&self) -> u32 {
    num::cast(
      match *self {
        GLType::Float => mem::size_of::<GLfloat>(),
        GLType::UInt  => mem::size_of::<GLuint>(),
        GLType::Int   => mem::size_of::<GLint>(),
      })
    .unwrap()
  }

  pub fn gl_enum(&self) -> GLenum {
    match *self {
      GLType::Float => gl::FLOAT,
      GLType::UInt  => gl::UNSIGNED_INT,
      GLType::Int   => gl::INT,
    }
  }

  pub fn is_integral(&self) -> bool {
    match *self {
      GLType::Float => false,
      GLType::UInt  => true,
      GLType::Int   => true,
    }
  }
}

#[derive(Show)]
/// Specifies how to pass data from OpenGL to the vertex shaders.
pub struct VertexAttribData<'a> {
  /// Cooresponds to the shader's `input variable`.
  pub name: &'a str,
  /// The size of this attribute, in the provided units.
  pub size: u32,
  pub unit: GLType,
}

pub struct ArrayHandle<'a> {
  pub lifetime: ContravariantLifetime<'a>,
  pub gl_id: GLuint,
}

impl<'a> ArrayHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> ArrayHandle<'a> {
    let mut gl_id = 0;
    unsafe {
      gl::GenVertexArrays(1, &mut gl_id);
    }

    ArrayHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ArrayHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteVertexArrays(1, &self.gl_id);
    }
  }
}

/// A fixed-capacity array of bytes passed to OpenGL.
pub struct GLArray<'a, T> {
  pub buffer: GLBuffer<'a, T>,
  pub handle: ArrayHandle<'a>,
  /// How to draw this buffer. Ex: gl::LINES, gl::TRIANGLES, etc.
  pub mode: GLenum,
  /// length in `T`s.
  pub length: usize,
}

impl<'a, T> GLArray<'a, T> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    _gl_context: &mut GLContext,
    shader_program: Rc<RefCell<Shader>>,
    attribs: &[VertexAttribData],
    mode: DrawMode,
    buffer: GLBuffer<'a, T>,
  ) -> GLArray<'a, T> {
    let handle = ArrayHandle::new(gl);

    unsafe {
      gl::BindVertexArray(handle.gl_id);
    }

    let mut offset = 0;
    let attrib_span = {
      let mut attrib_span = 0;
      for attrib in attribs.iter() {
        attrib_span += attrib.size * attrib.unit.size();
      }
      attrib_span
    };
    for attrib in attribs.iter() {
      let shader_attrib =
        glGetAttribLocation(
          shader_program.borrow().handle.gl_id,
          attrib.name
        );
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);
      let shader_attrib = shader_attrib as GLuint;

      unsafe {
        gl::EnableVertexAttribArray(shader_attrib);

        if attrib.unit.is_integral() {
          gl::VertexAttribIPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        } else {
          gl::VertexAttribPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            gl::FALSE as GLboolean,
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        }
      }
      offset += (attrib.size * attrib.unit.size()) as isize;
    }

    match unsafe { gl::GetError() } {
      gl::NO_ERROR => {},
      err => warn!("OpenGL error 0x{:x}", err),
    }

    assert_eq!(attrib_span as usize, mem::size_of::<T>());

    let length = buffer.byte_buffer.length / mem::size_of::<T>();

    GLArray {
      buffer: buffer,
      handle: handle,
      mode: mode.to_enum(),
      length: length,
    }
  }

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.handle.gl_id);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.buffer.byte_buffer.handle.gl_id);
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    self.buffer.push(gl, vs);
    self.length += vs.len();
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.buffer.swap_remove(gl, idx, count);
    self.length -= count;
  }

  /// Draws all the queued triangles to the screen.
  pub fn draw(&self, gl: &mut GLContext) {
    self.draw_slice(gl, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  pub fn draw_slice(&self, _gl: &mut GLContext, start: usize, len: usize) {
    assert!(start + len <= self.length);

    unsafe {
      gl::DrawArrays(self.mode, start as i32, len as i32);
    }
  }
}
<commit_msg>Remove Rc<RefCell<T>><commit_after>use gl;
use gl::types::*;
use gl_context::{GLContext, GLContextExistence};
use shader::*;
use std::ffi::CString;
use std::marker::ContravariantLifetime;
use std::mem;
use std::num;
use std::ptr;

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case)]
pub fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  let c_str = CString::from_slice(name.as_bytes());
  let ptr = c_str.as_ptr() as *const i8;
  unsafe {
    gl::GetAttribLocation(shader_program, ptr)
  }
}

pub struct BufferHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> BufferHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> BufferHandle<'a> {
    let mut gl_id = 0;

    unsafe {
      gl::GenBuffers(1, &mut gl_id);
    }

    assert!(gl_id != 0);

    BufferHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for BufferHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.gl_id);
    }
  }
}

/// Fixed-size VRAM buffer for individual bytes.
pub struct GLByteBuffer<'a> {
  pub handle: BufferHandle<'a>,
  /// number of bytes in the buffer.
  pub length: usize,
  /// maximum number of bytes in the buffer.
  pub capacity: usize,
}

impl<'a> GLByteBuffer<'a> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: usize,
  ) -> GLByteBuffer<'a> {
    let handle = BufferHandle::new(gl);

    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, handle.gl_id);

      gl::BufferData(
        gl::ARRAY_BUFFER,
        capacity as GLsizeiptr,
        ptr::null(),
        gl::DYNAMIC_DRAW,
      );
    }

    match gl_context.get_error() {
      gl::NO_ERROR => {},
      gl::OUT_OF_MEMORY => panic!("Out of VRAM"),
      err => warn!("OpenGL error 0x{:x}", err),
    }

    GLByteBuffer {
      handle: handle,
      length: 0,
      capacity: capacity,
    }
  }

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);
    }
  }

  /// Add more data into this buffer.
  pub unsafe fn push(&mut self, gl: &mut GLContext, vs: *const u8, count: usize) {
    assert!(
      self.length + count <= self.capacity,
      "GLByteBuffer::push {} into a {}/{} full GLByteBuffer",
      count,
      self.length,
      self.capacity
    );

    self.update_inner(gl, self.length, vs, count);
    self.length += count;
  }

  pub fn swap_remove(&mut self, _gl: &mut GLContext, i: usize, count: usize) {
    assert!(count <= self.length);
    self.length -= count;
    assert!(i <= self.length);

    // In the `i == self.length` case, we don't bother with the swap;
    // decreasing `self.length` is enough.

    if i < self.length {
      assert!(
        i <= self.length - count,
        "GLByteBuffer::swap_remove would cause copy in overlapping regions"
      );

      unsafe {
        gl::CopyBufferSubData(
          gl::ARRAY_BUFFER,
          gl::ARRAY_BUFFER,
          self.length as i64,
          i as i64,
          count as i64,
        );
      }
    }
  }

  pub unsafe fn update(&self, gl: &mut GLContext, idx: usize, vs: *const u8, count: usize) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

  unsafe fn update_inner(
    &self,
    _gl: &mut GLContext,
    idx: usize,
    vs: *const u8,
    count: usize,
  ) {
    assert!(idx + count <= self.capacity);

    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      idx as i64,
      count as i64,
      mem::transmute(vs)
    );
  }
}

/// Fixed-size typed VRAM buffer, optimized for bulk inserts.
pub struct GLBuffer<'a, T> {
  pub byte_buffer: GLByteBuffer<'a>,
}

impl<'a, T> GLBuffer<'a, T> {
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    capacity: usize,
  ) -> GLBuffer<'a, T> {
    GLBuffer {
      byte_buffer: GLByteBuffer::new(gl, gl_context, capacity * mem::size_of::<T>()),
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    unsafe {
      self.byte_buffer.push(
        gl,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len()
      );
    }
  }

  pub fn update(&mut self, gl: &mut GLContext, idx: usize, vs: &[T]) {
    unsafe {
      self.byte_buffer.update(
        gl,
        mem::size_of::<T>() * idx,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len(),
      );
    }
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.byte_buffer.swap_remove(
      gl,
      mem::size_of::<T>() * idx,
      mem::size_of::<T>() * count,
    );
  }
}

#[derive(Show)]
#[derive(Copy, Clone)]
pub enum DrawMode {
  Lines,
  Triangles,
  Points,
}

impl DrawMode {
  fn to_enum(&self) -> GLenum {
    match *self {
      DrawMode::Lines     => gl::LINES,
      DrawMode::Triangles => gl::TRIANGLES,
      DrawMode::Points    => gl::POINTS,
    }
  }
}

#[derive(Show)]
#[derive(Copy, Clone)]
pub enum GLType {
  Float,
  UInt,
  Int,
}

impl GLType {
  pub fn size(&self) -> u32 {
    num::cast(
      match *self {
        GLType::Float => mem::size_of::<GLfloat>(),
        GLType::UInt  => mem::size_of::<GLuint>(),
        GLType::Int   => mem::size_of::<GLint>(),
      })
    .unwrap()
  }

  pub fn gl_enum(&self) -> GLenum {
    match *self {
      GLType::Float => gl::FLOAT,
      GLType::UInt  => gl::UNSIGNED_INT,
      GLType::Int   => gl::INT,
    }
  }

  pub fn is_integral(&self) -> bool {
    match *self {
      GLType::Float => false,
      GLType::UInt  => true,
      GLType::Int   => true,
    }
  }
}

#[derive(Show)]
/// Specifies how to pass data from OpenGL to the vertex shaders.
pub struct VertexAttribData<'a> {
  /// Cooresponds to the shader's `input variable`.
  pub name: &'a str,
  /// The size of this attribute, in the provided units.
  pub size: u32,
  pub unit: GLType,
}

pub struct ArrayHandle<'a> {
  pub lifetime: ContravariantLifetime<'a>,
  pub gl_id: GLuint,
}

impl<'a> ArrayHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> ArrayHandle<'a> {
    let mut gl_id = 0;
    unsafe {
      gl::GenVertexArrays(1, &mut gl_id);
    }

    ArrayHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ArrayHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteVertexArrays(1, &self.gl_id);
    }
  }
}

/// A fixed-capacity array of bytes passed to OpenGL.
pub struct GLArray<'a, T> {
  pub buffer: GLBuffer<'a, T>,
  pub handle: ArrayHandle<'a>,
  /// How to draw this buffer. Ex: gl::LINES, gl::TRIANGLES, etc.
  pub mode: GLenum,
  /// length in `T`s.
  pub length: usize,
}

impl<'a, T> GLArray<'a, T> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new(
    gl: &'a GLContextExistence,
    _gl_context: &mut GLContext,
    shader_program: &Shader<'a>,
    attribs: &[VertexAttribData],
    mode: DrawMode,
    buffer: GLBuffer<'a, T>,
  ) -> GLArray<'a, T> {
    let handle = ArrayHandle::new(gl);

    unsafe {
      gl::BindVertexArray(handle.gl_id);
    }

    let mut offset = 0;
    let attrib_span = {
      let mut attrib_span = 0;
      for attrib in attribs.iter() {
        attrib_span += attrib.size * attrib.unit.size();
      }
      attrib_span
    };
    for attrib in attribs.iter() {
      let shader_attrib =
        glGetAttribLocation(
          shader_program.handle.gl_id,
          attrib.name
        );
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);
      let shader_attrib = shader_attrib as GLuint;

      unsafe {
        gl::EnableVertexAttribArray(shader_attrib);

        if attrib.unit.is_integral() {
          gl::VertexAttribIPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        } else {
          gl::VertexAttribPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            gl::FALSE as GLboolean,
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        }
      }
      offset += (attrib.size * attrib.unit.size()) as isize;
    }

    match unsafe { gl::GetError() } {
      gl::NO_ERROR => {},
      err => warn!("OpenGL error 0x{:x}", err),
    }

    assert_eq!(attrib_span as usize, mem::size_of::<T>());

    let length = buffer.byte_buffer.length / mem::size_of::<T>();

    GLArray {
      buffer: buffer,
      handle: handle,
      mode: mode.to_enum(),
      length: length,
    }
  }

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.handle.gl_id);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.buffer.byte_buffer.handle.gl_id);
    }
  }

  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) {
    self.buffer.push(gl, vs);
    self.length += vs.len();
  }

  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.buffer.swap_remove(gl, idx, count);
    self.length -= count;
  }

  /// Draws all the queued triangles to the screen.
  pub fn draw(&self, gl: &mut GLContext) {
    self.draw_slice(gl, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  pub fn draw_slice(&self, _gl: &mut GLContext, start: usize, len: usize) {
    assert!(start + len <= self.length);

    unsafe {
      gl::DrawArrays(self.mode, start as i32, len as i32);
    }
  }
}
<|endoftext|>


<commit_before>use game::gfx::{CopySprite, Sprite};
use game::{Game};
use game::data::Rectangle;
use sdl2::render::Renderer;
use conv::prelude::*;
use sdl2::rect::Rect as SdlRect;

pub const TERRAIN_W: f64 = 500.0;
pub const TERRAIN_H: f64 = 250.0;

pub const TILES_PCS_W: usize = 160;
pub const TILES_PCS_H: usize = 100;

const TILES_W: f64 = 100.0;
const TILES_H: f64 = 50.0;

#[derive(Clone, Copy)]
pub enum TerrainFrame {
  Sand = 0,
  Grass = 1,
}

#[derive(Clone)]
pub struct TerrainTile {
  pub rect: Rectangle,
  pub terrain_sprites: Vec<Sprite>,
  pub current: TerrainFrame,
}

#[derive(Clone)]
pub struct Tilemap {
  pub pos: f64,
  pub sprite: Sprite,
}

pub fn cartesian_to_isometric(point_x: i32, point_y: i32) -> (i32, i32) {
  let x = point_x - point_y;
  let y = (point_x + point_y) / 2;
  (x,y)
}

pub fn get_tiles(game: &Game) -> Vec<TerrainTile> {
  let terrain_spritesheet = Sprite::load(&game.renderer, "assets/terrain.png").unwrap();
  let mut terrain_sprites = Vec::with_capacity(TILES_PCS_W );
  let mut tiles = Vec::with_capacity(TILES_PCS_W * TILES_PCS_H * 2);

  for x in 0..3 {
    terrain_sprites.push(terrain_spritesheet.region(Rectangle {
      w: TILES_W,
      h: TILES_H,
      x: TILES_W * x as f64,
      y: 0.0 as f64,
    }).unwrap());
  }

  for x in 0..TILES_PCS_W {
    for y in 0..TILES_PCS_H {
      let x2: f64 = TILES_W * 1.5 as f64;
      let y2: f64 = TILES_H * 1.5 as f64;
      tiles.push(TerrainTile {
        rect: Rectangle {
          x: TILES_W * x as f64,
          y: TILES_H * y as f64,
          w: TILES_W,
          h: TILES_H,
        },
        terrain_sprites: terrain_sprites.clone(),
        current: TerrainFrame::Grass,
      });

      tiles.push(TerrainTile {
        rect: Rectangle {
          x: TILES_W * f64::value_from((x + 1)).unwrap() - x2 as f64,
          y: TILES_H * f64::value_from((y + 1)).unwrap() - y2 as f64,
          w: TILES_W,
          h: TILES_H,
        },
        terrain_sprites: terrain_sprites.clone(),
        current: TerrainFrame::Sand,
      });
    }
  }
  tiles
}

pub fn viewport_move(game: &Game, curr_rect: SdlRect) -> Rectangle {
  if game.events.move_right == true {
    Rectangle {
      x: f64::value_from(curr_rect.x() - 3).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_left == true {
    Rectangle {
      x: f64::value_from(curr_rect.x() + 3).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_up == true {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y() + 3).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_down == true {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y() - 3).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  }
}
<commit_msg>Convertion projection to use traditional isometric projection '<>'<commit_after>use game::gfx::{CopySprite, Sprite};
use game::{Game};
use game::data::Rectangle;
use sdl2::render::Renderer;
use conv::prelude::*;
use sdl2::rect::Rect as SdlRect;

pub const TERRAIN_W: f64 = 500.0;
pub const TERRAIN_H: f64 = 250.0;

pub const TILES_PCS_W: usize = 18;
pub const TILES_PCS_H: usize = 36;

const TILES_W: f64 = 100.0;
const TILES_H: f64 = 50.0;

#[derive(Clone, Copy)]
pub enum TerrainFrame {
  Sand = 0,
  Grass = 1,
}

#[derive(Clone)]
pub struct TerrainTile {
  pub rect: Rectangle,
  pub terrain_sprites: Vec<Sprite>,
  pub current: TerrainFrame,
}

#[derive(Clone)]
pub struct Tilemap {
  pub pos: f64,
  pub sprite: Sprite,
}

#[derive(Clone)]
pub struct Point {
  x: f64,
  y: f64,
}

pub fn cartesian_to_isometric(point_x: f64, point_y: f64) -> Point {
  Point {
    x: (point_x - point_y) / 2.0,
    y: (point_x + point_y) / 4.0
  }
}

pub fn get_tiles(game: &Game) -> Vec<TerrainTile> {
  let terrain_spritesheet = Sprite::load(&game.renderer, "assets/terrain.png").unwrap();
  let mut terrain_sprites = Vec::with_capacity(TILES_PCS_W );
  let mut tiles = Vec::with_capacity(TILES_PCS_W * TILES_PCS_H * 2);

  for x in 0..3 {
    terrain_sprites.push(terrain_spritesheet.region(Rectangle {
      w: TILES_W,
      h: TILES_H,
      x: TILES_W * x as f64,
      y: 0.0 as f64,
    }).unwrap());
  }

  for x in 0..TILES_PCS_W {
    for y in 0..TILES_PCS_H {
      let point = cartesian_to_isometric(TILES_W * x as f64, TILES_H * y as f64);
      tiles.push(TerrainTile {
        rect: Rectangle {
          x: TILES_W * x as f64,
          y: TILES_H * y as f64,
          w: TILES_W,
          h: TILES_H,
        },
        terrain_sprites: terrain_sprites.clone(),
        current: TerrainFrame::Grass,
      });
    }
  }
  tiles
}

pub fn viewport_move(game: &Game, curr_rect: SdlRect) -> Rectangle {
  if game.events.move_right == true {
    Rectangle {
      x: f64::value_from(curr_rect.x() - 3).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_left == true {
    Rectangle {
      x: f64::value_from(curr_rect.x() + 3).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_up == true {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y() + 3).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_down == true {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y() - 3).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  }
}
<|endoftext|>


<commit_before>//! Check logic for instructions

use util::bigint::{U256, M256};
use util::gas::Gas;

use vm::{Memory, Instruction};
use vm::errors::{MachineError, EvalError};

use vm::eval::{State, ControlCheck};
use super::util::check_range;

#[allow(unused_variables)]
pub fn extra_check_opcode<M: Memory + Default>(instruction: Instruction, state: &State<M>, stipend_gas: Gas, after_gas: Gas) -> Result<(), EvalError> {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE | Instruction::DELEGATECALL => {
            if after_gas < state.stack.peek(0).unwrap().into() {
                Err(EvalError::Machine(MachineError::EmptyGas))
            } else {
                Ok(())
            }
        },
        _ => Ok(())
    }
}

#[allow(unused_variables)]
/// Check whether `run_opcode` would fail without mutating any of the
/// machine state.
pub fn check_opcode<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Result<Option<ControlCheck>, EvalError> {
    match instruction {
        Instruction::STOP => Ok(None),
        Instruction::ADD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::MUL => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SUB => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::DIV => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SDIV => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::MOD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SMOD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::ADDMOD => { state.stack.check_pop_push(3, 1)?; Ok(None) },
        Instruction::MULMOD => { state.stack.check_pop_push(3, 1)?; Ok(None) },
        Instruction::EXP => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SIGNEXTEND => { state.stack.check_pop_push(2, 1)?; Ok(None) },

        Instruction::LT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::GT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SLT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SGT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::EQ => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::ISZERO => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::AND => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::OR => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::XOR => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::NOT => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::BYTE => { state.stack.check_pop_push(2, 1)?; Ok(None) },

        Instruction::SHA3 => {
            state.stack.check_pop_push(2, 1)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },

        Instruction::ADDRESS => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::BALANCE => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require(state.stack.peek(0).unwrap().into())?;
            Ok(None)
        },
        Instruction::ORIGIN => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLER => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLVALUE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLDATALOAD => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::CALLDATASIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLDATACOPY => {
            state.stack.check_pop_push(3, 0)?;
            state.memory.check_write_range(
                state.stack.peek(0).unwrap(), state.stack.peek(2).unwrap())?;
            Ok(None)
        },
        Instruction::CODESIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CODECOPY => {
            state.stack.check_pop_push(3, 0)?;
            state.memory.check_write_range(
                state.stack.peek(0).unwrap(), state.stack.peek(2).unwrap())?;
            Ok(None)
        },
        Instruction::GASPRICE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::EXTCODESIZE => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require_code(state.stack.peek(0).unwrap().into())?;
            Ok(None)
        },
        Instruction::EXTCODECOPY => {
            state.stack.check_pop_push(4, 0)?;
            state.account_state.require_code(state.stack.peek(0).unwrap().into())?;
            state.memory.check_write_range(
                state.stack.peek(1).unwrap(), state.stack.peek(3).unwrap())?;
            Ok(None)
        },

        Instruction::BLOCKHASH => {
            state.stack.check_pop_push(1, 1)?;
            let current_number = state.block.number;
            let number = state.stack.peek(0).unwrap();
            if !(number >= current_number || current_number - number > M256::from(256u64)) {
                state.blockhash_state.get(number)?;
            }
            Ok(None)
        },
        Instruction::COINBASE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::TIMESTAMP => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::NUMBER => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::DIFFICULTY => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::GASLIMIT => { state.stack.check_pop_push(0, 1)?; Ok(None) },

        Instruction::POP => { state.stack.check_pop_push(1, 0)?; Ok(None) },
        Instruction::MLOAD => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::MSTORE => {
            state.stack.check_pop_push(2, 0)?;
            state.memory.check_write(state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::MSTORE8 => {
            state.stack.check_pop_push(2, 0)?;
            state.memory.check_write(state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::SLOAD => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require(state.context.address)?;
            state.account_state.require_storage(state.context.address, state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::SSTORE => {
            state.stack.check_pop_push(2, 0)?;
            state.account_state.require(state.context.address)?;
            state.account_state.require_storage(state.context.address, state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::JUMP => {
            state.stack.check_pop_push(1, 0)?;
            Ok(Some(ControlCheck::Jump(state.stack.peek(0).unwrap())))
        },
        Instruction::JUMPI => {
            state.stack.check_pop_push(2, 0)?;
            if state.stack.peek(1).unwrap() != M256::zero() {
                Ok(Some(ControlCheck::Jump(state.stack.peek(0).unwrap())))
            } else {
                Ok(None)
            }
        },
        Instruction::PC => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::MSIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::GAS => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::JUMPDEST => Ok(None),

        Instruction::PUSH(v) => { state.stack.check_pop_push(0, 1)?; Ok(None) },

        Instruction::DUP(v) => { state.stack.check_pop_push(v, v+1)?; Ok(None) },
        Instruction::SWAP(v) => { state.stack.check_pop_push(v+1, v+1)?; Ok(None) },

        Instruction::LOG(v) => {
            state.stack.check_pop_push(v+2, 0)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },
        Instruction::CREATE => {
            state.stack.check_pop_push(3, 1)?;
            check_range(state.stack.peek(1).unwrap(), state.stack.peek(2).unwrap())?;
            state.account_state.require(state.context.address)?;
            Ok(None)
        },
        Instruction::CALL => {
            state.stack.check_pop_push(7, 1)?;
            check_range(state.stack.peek(3).unwrap(), state.stack.peek(4).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(5).unwrap(), state.stack.peek(6).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::CALLCODE => {
            state.stack.check_pop_push(7, 1)?;
            check_range(state.stack.peek(3).unwrap(), state.stack.peek(4).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(5).unwrap(), state.stack.peek(6).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::RETURN => {
            state.stack.check_pop_push(2, 0)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },
        Instruction::DELEGATECALL => {
            state.stack.check_pop_push(6, 1)?;
            check_range(state.stack.peek(2).unwrap(), state.stack.peek(3).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(4).unwrap(), state.stack.peek(5).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::SUICIDE => {
            state.stack.check_pop_push(1, 0)?;
            state.account_state.require(state.context.address)?;
            let balance = state.account_state.balance(state.context.address).unwrap();
            if state.patch.ignore_suicide_zero_balance && balance == U256::zero() {
                // Do not require target account in this case.
            } else {
                state.account_state.require(state.stack.peek(0).unwrap().into())?;
            }
            Ok(None)
        },
    }
}
<commit_msg>Revert "check: undefined U256"<commit_after>//! Check logic for instructions

use util::bigint::M256;
use util::gas::Gas;

use vm::{Memory, Instruction};
use vm::errors::{MachineError, EvalError};

use vm::eval::{State, ControlCheck};
use super::util::check_range;

#[allow(unused_variables)]
pub fn extra_check_opcode<M: Memory + Default>(instruction: Instruction, state: &State<M>, stipend_gas: Gas, after_gas: Gas) -> Result<(), EvalError> {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE | Instruction::DELEGATECALL => {
            if after_gas < state.stack.peek(0).unwrap().into() {
                Err(EvalError::Machine(MachineError::EmptyGas))
            } else {
                Ok(())
            }
        },
        _ => Ok(())
    }
}

#[allow(unused_variables)]
/// Check whether `run_opcode` would fail without mutating any of the
/// machine state.
pub fn check_opcode<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Result<Option<ControlCheck>, EvalError> {
    match instruction {
        Instruction::STOP => Ok(None),
        Instruction::ADD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::MUL => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SUB => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::DIV => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SDIV => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::MOD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SMOD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::ADDMOD => { state.stack.check_pop_push(3, 1)?; Ok(None) },
        Instruction::MULMOD => { state.stack.check_pop_push(3, 1)?; Ok(None) },
        Instruction::EXP => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SIGNEXTEND => { state.stack.check_pop_push(2, 1)?; Ok(None) },

        Instruction::LT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::GT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SLT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SGT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::EQ => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::ISZERO => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::AND => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::OR => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::XOR => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::NOT => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::BYTE => { state.stack.check_pop_push(2, 1)?; Ok(None) },

        Instruction::SHA3 => {
            state.stack.check_pop_push(2, 1)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },

        Instruction::ADDRESS => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::BALANCE => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require(state.stack.peek(0).unwrap().into())?;
            Ok(None)
        },
        Instruction::ORIGIN => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLER => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLVALUE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLDATALOAD => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::CALLDATASIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLDATACOPY => {
            state.stack.check_pop_push(3, 0)?;
            state.memory.check_write_range(
                state.stack.peek(0).unwrap(), state.stack.peek(2).unwrap())?;
            Ok(None)
        },
        Instruction::CODESIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CODECOPY => {
            state.stack.check_pop_push(3, 0)?;
            state.memory.check_write_range(
                state.stack.peek(0).unwrap(), state.stack.peek(2).unwrap())?;
            Ok(None)
        },
        Instruction::GASPRICE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::EXTCODESIZE => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require_code(state.stack.peek(0).unwrap().into())?;
            Ok(None)
        },
        Instruction::EXTCODECOPY => {
            state.stack.check_pop_push(4, 0)?;
            state.account_state.require_code(state.stack.peek(0).unwrap().into())?;
            state.memory.check_write_range(
                state.stack.peek(1).unwrap(), state.stack.peek(3).unwrap())?;
            Ok(None)
        },

        Instruction::BLOCKHASH => {
            state.stack.check_pop_push(1, 1)?;
            let current_number = state.block.number;
            let number = state.stack.peek(0).unwrap();
            if !(number >= current_number || current_number - number > M256::from(256u64)) {
                state.blockhash_state.get(number)?;
            }
            Ok(None)
        },
        Instruction::COINBASE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::TIMESTAMP => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::NUMBER => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::DIFFICULTY => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::GASLIMIT => { state.stack.check_pop_push(0, 1)?; Ok(None) },

        Instruction::POP => { state.stack.check_pop_push(1, 0)?; Ok(None) },
        Instruction::MLOAD => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::MSTORE => {
            state.stack.check_pop_push(2, 0)?;
            state.memory.check_write(state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::MSTORE8 => {
            state.stack.check_pop_push(2, 0)?;
            state.memory.check_write(state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::SLOAD => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require(state.context.address)?;
            state.account_state.require_storage(state.context.address, state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::SSTORE => {
            state.stack.check_pop_push(2, 0)?;
            state.account_state.require(state.context.address)?;
            state.account_state.require_storage(state.context.address, state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::JUMP => {
            state.stack.check_pop_push(1, 0)?;
            Ok(Some(ControlCheck::Jump(state.stack.peek(0).unwrap())))
        },
        Instruction::JUMPI => {
            state.stack.check_pop_push(2, 0)?;
            if state.stack.peek(1).unwrap() != M256::zero() {
                Ok(Some(ControlCheck::Jump(state.stack.peek(0).unwrap())))
            } else {
                Ok(None)
            }
        },
        Instruction::PC => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::MSIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::GAS => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::JUMPDEST => Ok(None),

        Instruction::PUSH(v) => { state.stack.check_pop_push(0, 1)?; Ok(None) },

        Instruction::DUP(v) => { state.stack.check_pop_push(v, v+1)?; Ok(None) },
        Instruction::SWAP(v) => { state.stack.check_pop_push(v+1, v+1)?; Ok(None) },

        Instruction::LOG(v) => {
            state.stack.check_pop_push(v+2, 0)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },
        Instruction::CREATE => {
            state.stack.check_pop_push(3, 1)?;
            check_range(state.stack.peek(1).unwrap(), state.stack.peek(2).unwrap())?;
            state.account_state.require(state.context.address)?;
            Ok(None)
        },
        Instruction::CALL => {
            state.stack.check_pop_push(7, 1)?;
            check_range(state.stack.peek(3).unwrap(), state.stack.peek(4).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(5).unwrap(), state.stack.peek(6).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::CALLCODE => {
            state.stack.check_pop_push(7, 1)?;
            check_range(state.stack.peek(3).unwrap(), state.stack.peek(4).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(5).unwrap(), state.stack.peek(6).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::RETURN => {
            state.stack.check_pop_push(2, 0)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },
        Instruction::DELEGATECALL => {
            state.stack.check_pop_push(6, 1)?;
            check_range(state.stack.peek(2).unwrap(), state.stack.peek(3).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(4).unwrap(), state.stack.peek(5).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::SUICIDE => {
            state.stack.check_pop_push(1, 0)?;
            state.account_state.require(state.context.address)?;
            let balance = state.account_state.balance(state.context.address).unwrap();
            if state.patch.ignore_suicide_zero_balance && balance == U256::zero() {
                // Do not require target account in this case.
            } else {
                state.account_state.require(state.stack.peek(0).unwrap().into())?;
            }
            Ok(None)
        },
    }
}
<|endoftext|>


<commit_before>//! A Rust interface for Objective-C blocks.
//!
//! For more information on the specifics of the block implementation, see
//! Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html

use std::mem;
use std::ptr;
use libc::{c_int, c_ulong};

use runtime::Class;
use {Id, Message};

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
    static _NSConcreteStackBlock: Class;
}

/// An invoke function for a `Block`; this is the raw C function called by the
/// Objective-C runtime.
type BlockInvoke<A, R> = unsafe extern fn(*mut Block<A, R>, ...) -> R;

/// An invoke function for a `ConcreteBlock`; this is the raw C function called
/// by the Objective-C runtime.
pub type ConcreteBlockInvoke<A, R, F> =
    unsafe extern fn(*mut ConcreteBlock<A, R, F>, ...) -> R;

/// Types that may be used as the arguments to an Objective-C block.
pub trait BlockArguments {
    /// Calls the given `Block` with self as the arguments.
    fn call_block<R>(self, block: &Block<Self, R>) -> R;

    /// Returns an invoke function for a `ConcreteBlock` that takes this type
    /// of arguments.
    fn invoke_for_concrete_block<R, F: Fn<Self, R>>() -> ConcreteBlockInvoke<Self, R, F>;
}

macro_rules! block_args_impl(
    ($f:ident $(, $a:ident : $t:ident)*) => (
        impl<$($t),*> BlockArguments for ($($t,)*) {
            fn call_block<R>(self, block: &Block<Self, R>) -> R {
                let invoke: unsafe extern fn(*mut Block<Self, R> $(, $t)*) -> R = unsafe {
                    mem::transmute(block.invoke)
                };
                let ($($a,)*) = self;
                let block_ptr = block as *const _ as *mut _;
                unsafe {
                    invoke(block_ptr $(, $a)*)
                }
            }

            fn invoke_for_concrete_block<R, X: Fn<Self, R>>() ->
                    ConcreteBlockInvoke<Self, R, X> {
                unsafe extern fn $f<R, X: Fn<Self, R> $(, $t)*>(
                        block_ptr: *mut ConcreteBlock<Self, R, X>
                        $(, $a: $t)*) -> R {
                    let block = &*block_ptr;
                    (block.closure)($($a),*)
                }

                unsafe {
                    mem::transmute($f::<R, X $(, $t)*>)
                }
            }
        }
    );
);

block_args_impl!(concrete_block_invoke_args0);
block_args_impl!(concrete_block_invoke_args1, a: A);
block_args_impl!(concrete_block_invoke_args2, a: A, b: B);
block_args_impl!(concrete_block_invoke_args3, a: A, b: B, c: C);
block_args_impl!(concrete_block_invoke_args4, a: A, b: B, c: C, d: D);
block_args_impl!(concrete_block_invoke_args5, a: A, b: B, c: C, d: D, e: E);
block_args_impl!(concrete_block_invoke_args6, a: A, b: B, c: C, d: D, e: E, f: F);
block_args_impl!(concrete_block_invoke_args7, a: A, b: B, c: C, d: D, e: E, f: F, g: G);
block_args_impl!(concrete_block_invoke_args8, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
block_args_impl!(concrete_block_invoke_args9, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
block_args_impl!(concrete_block_invoke_args10, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
block_args_impl!(concrete_block_invoke_args11, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
block_args_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

/// An Objective-C block that takes arguments of `A` when called and
/// returns a value of `R`.
#[repr(C)]
pub struct Block<A: BlockArguments, R> {
    isa: *const Class,
    flags: c_int,
    _reserved: c_int,
    invoke: BlockInvoke<A, R>,
}

impl<A: BlockArguments, R> Fn<A, R> for Block<A, R> {
    /// Call self with the given arguments.
    extern "rust-call" fn call(&self, args: A) -> R {
        args.call_block(self)
    }
}

impl<A: BlockArguments, R> Message for Block<A, R> { }

/// An Objective-C block whose size is known at compile time and may be
/// constructed on the stack.
#[repr(C)]
pub struct ConcreteBlock<A: BlockArguments, R, F> {
    base: Block<A, R>,
    descriptor: Box<BlockDescriptor<ConcreteBlock<A, R, F>>>,
    closure: F,
}

impl<A: BlockArguments, R, F: Fn<A, R>> ConcreteBlock<A, R, F> {
    pub fn new(closure: F) -> Self {
        let extern_invoke: ConcreteBlockInvoke<A, R, F> =
            BlockArguments::invoke_for_concrete_block();
        ConcreteBlock {
            base: Block {
                isa: &_NSConcreteStackBlock,
                // 1 << 25 = BLOCK_HAS_COPY_DISPOSE
                flags: 1 << 25,
                _reserved: 0,
                invoke: unsafe { mem::transmute(extern_invoke) },
            },
            descriptor: box BlockDescriptor::<Self>::new(),
            closure: closure,
        }
    }

    /// Copy self onto the heap.
    pub fn copy(self) -> Id<Block<A, R>> {
        unsafe {
            let block = msg_send![&self.base copy] as *mut Block<A, R>;
            // At this point, our copy helper has been run so the block will
            // be moved to the heap and we can forget the original block
            // because the heap block will drop in our dispose helper.
            mem::forget(self);
            Id::from_retained_ptr(block)
        }
    }
}

impl<A: BlockArguments, R, F: Fn<A, R> + Clone> Clone for ConcreteBlock<A, R, F> {
    fn clone(&self) -> Self {
        ConcreteBlock::new(self.closure.clone())
    }
}

impl<A: BlockArguments, R, F> Deref<Block<A, R>> for ConcreteBlock<A, R, F> {
    fn deref(&self) -> &Block<A, R> {
        &self.base
    }
}

impl<A: BlockArguments, R, F: Fn<A, R>> Fn<A, R> for ConcreteBlock<A, R, F> {
    extern "rust-call" fn call(&self, args: A) -> R {
        self.closure.call(args)
    }
}

unsafe extern fn block_context_dispose<B>(block: &mut B) {
    // Read the block onto the stack and let it drop
    ptr::read(block);
}

unsafe extern fn block_context_copy<B>(_dst: &mut B, _src: &B) {
    // The runtime memmoves the src block into the dst block, nothing to do
}

#[repr(C)]
struct BlockDescriptor<B> {
    _reserved: c_ulong,
    block_size: c_ulong,
    copy_helper: unsafe extern fn(&mut B, &B),
    dispose_helper: unsafe extern fn(&mut B),
}

impl<B> BlockDescriptor<B> {
    fn new() -> BlockDescriptor<B> {
        BlockDescriptor {
            _reserved: 0,
            block_size: mem::size_of::<B>() as c_ulong,
            copy_helper: block_context_copy::<B>,
            dispose_helper: block_context_dispose::<B>,
        }
    }
}

#[cfg(test)]
mod tests {
    use Id;
    use objc_test_utils;
    use super::{Block, ConcreteBlock};

    fn get_int_block() -> &'static Block<(), int> {
        unsafe {
            &*(objc_test_utils::get_int_block() as *const _)
        }
    }

    fn get_int_block_with(i: int) -> Id<Block<(), int>> {
        unsafe {
            let ptr = objc_test_utils::get_int_block_with(i);
            Id::from_retained_ptr(ptr as *mut _)
        }
    }

    fn get_add_block() -> &'static Block<(int,), int> {
        unsafe {
            &*(objc_test_utils::get_add_block() as *const _)
        }
    }

    fn get_add_block_with(i: int) -> Id<Block<(int,), int>> {
        unsafe {
            let ptr = objc_test_utils::get_add_block_with(i);
            Id::from_retained_ptr(ptr as *mut _)
        }
    }

    fn invoke_int_block(block: &Block<(), int>) -> int {
        let ptr = block as *const _;
        unsafe {
            objc_test_utils::invoke_int_block(ptr as *const _)
        }
    }

    fn invoke_add_block(block: &Block<(int,), int>, a: int) -> int {
        let ptr = block as *const _;
        unsafe {
            objc_test_utils::invoke_add_block(ptr as *const _, a)
        }
    }

    #[test]
    fn test_call_block() {
        let block = get_int_block();
        assert!((*block)() == 7);

        let block = get_int_block_with(13);
        assert!((*block)() == 13);
    }

    #[test]
    fn test_call_block_args() {
        let block = get_add_block();
        assert!((*block)(2) == 9);

        let block = get_add_block_with(13);
        assert!((*block)(2) == 15);
    }

    #[test]
    fn test_create_block() {
        let block = ConcreteBlock::new(|&:| 13);
        let result = invoke_int_block(&*block);
        assert!(result == 13);
    }

    #[test]
    fn test_create_block_args() {
        let block = ConcreteBlock::new(|&: a: int| a + 5);
        let result = invoke_add_block(&*block, 6);
        assert!(result == 11);
    }

    #[test]
    fn test_concrete_block_copy() {
        let s = String::from_str("Hello!");
        let expected_len = s.len();
        let block = ConcreteBlock::new(move |&:| s.len());
        assert!((*block)() == expected_len);

        let copied = block.copy();
        assert!((*copied)() == expected_len);
    }
}
<commit_msg>Simplified ConcreteBlock declaration.<commit_after>//! A Rust interface for Objective-C blocks.
//!
//! For more information on the specifics of the block implementation, see
//! Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html

use std::mem;
use std::ptr;
use libc::{c_int, c_ulong};

use runtime::Class;
use {Id, Message};

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
    static _NSConcreteStackBlock: Class;
}

/// Types that may be used as the arguments to an Objective-C block.
pub trait BlockArguments {
    /// Calls the given `Block` with self as the arguments.
    fn call_block<R>(self, block: &Block<Self, R>) -> R;

    /// Returns an invoke function for a `ConcreteBlock` that takes this type
    /// of arguments.
    fn invoke_for_concrete_block<R, F: Fn<Self, R>>() ->
            unsafe extern fn(*mut ConcreteBlock<F>, ...) -> R;
}

macro_rules! block_args_impl(
    ($f:ident $(, $a:ident : $t:ident)*) => (
        impl<$($t),*> BlockArguments for ($($t,)*) {
            fn call_block<R>(self, block: &Block<Self, R>) -> R {
                let invoke: unsafe extern fn(*mut Block<Self, R> $(, $t)*) -> R = unsafe {
                    mem::transmute(block.invoke)
                };
                let ($($a,)*) = self;
                let block_ptr = block as *const _ as *mut _;
                unsafe {
                    invoke(block_ptr $(, $a)*)
                }
            }

            fn invoke_for_concrete_block<R, X: Fn<Self, R>>() ->
                    unsafe extern fn(*mut ConcreteBlock<X>, ...) -> R {
                unsafe extern fn $f<R, X: Fn<Self, R> $(, $t)*>(
                        block_ptr: *mut ConcreteBlock<X>
                        $(, $a: $t)*) -> R {
                    let block = &*block_ptr;
                    (block.closure)($($a),*)
                }

                unsafe {
                    mem::transmute($f::<R, X $(, $t)*>)
                }
            }
        }
    );
);

block_args_impl!(concrete_block_invoke_args0);
block_args_impl!(concrete_block_invoke_args1, a: A);
block_args_impl!(concrete_block_invoke_args2, a: A, b: B);
block_args_impl!(concrete_block_invoke_args3, a: A, b: B, c: C);
block_args_impl!(concrete_block_invoke_args4, a: A, b: B, c: C, d: D);
block_args_impl!(concrete_block_invoke_args5, a: A, b: B, c: C, d: D, e: E);
block_args_impl!(concrete_block_invoke_args6, a: A, b: B, c: C, d: D, e: E, f: F);
block_args_impl!(concrete_block_invoke_args7, a: A, b: B, c: C, d: D, e: E, f: F, g: G);
block_args_impl!(concrete_block_invoke_args8, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
block_args_impl!(concrete_block_invoke_args9, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
block_args_impl!(concrete_block_invoke_args10, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
block_args_impl!(concrete_block_invoke_args11, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
block_args_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

/// An Objective-C block that takes arguments of `A` when called and
/// returns a value of `R`.
#[repr(C)]
pub struct Block<A: BlockArguments, R> {
    isa: *const Class,
    flags: c_int,
    _reserved: c_int,
    invoke: unsafe extern fn(*mut Block<A, R>, ...) -> R,
}

impl<A: BlockArguments, R> Fn<A, R> for Block<A, R> {
    /// Call self with the given arguments.
    extern "rust-call" fn call(&self, args: A) -> R {
        args.call_block(self)
    }
}

impl<A: BlockArguments, R> Message for Block<A, R> { }

/// An Objective-C block whose size is known at compile time and may be
/// constructed on the stack.
#[repr(C)]
pub struct ConcreteBlock<F> {
    isa: *const Class,
    flags: c_int,
    _reserved: c_int,
    invoke: unsafe extern fn(*mut ConcreteBlock<F>, ...),
    descriptor: Box<BlockDescriptor<ConcreteBlock<F>>>,
    closure: F,
}

impl<A: BlockArguments, R, F: Fn<A, R>> ConcreteBlock<F> {
    pub fn new(closure: F) -> Self {
        let extern_invoke =
            BlockArguments::invoke_for_concrete_block::<R, F>();
        ConcreteBlock {
            isa: &_NSConcreteStackBlock,
            // 1 << 25 = BLOCK_HAS_COPY_DISPOSE
            flags: 1 << 25,
            _reserved: 0,
            invoke: unsafe { mem::transmute(extern_invoke) },
            descriptor: box BlockDescriptor::<Self>::new(),
            closure: closure,
        }
    }

    /// Copy self onto the heap.
    pub fn copy(self) -> Id<Block<A, R>> {
        unsafe {
            let block = msg_send![&*self copy] as *mut Block<A, R>;
            // At this point, our copy helper has been run so the block will
            // be moved to the heap and we can forget the original block
            // because the heap block will drop in our dispose helper.
            mem::forget(self);
            Id::from_retained_ptr(block)
        }
    }
}

impl<A: BlockArguments, R, F: Fn<A, R> + Clone> Clone for ConcreteBlock<F> {
    fn clone(&self) -> Self {
        ConcreteBlock::new(self.closure.clone())
    }
}

impl<A: BlockArguments, R, F: Fn<A, R>> Deref<Block<A, R>> for ConcreteBlock<F> {
    fn deref(&self) -> &Block<A, R> {
        let ptr = self as *const _ as *const Block<A, R>;
        unsafe { &*ptr }
    }
}

impl<A: BlockArguments, R, F: Fn<A, R>> Fn<A, R> for ConcreteBlock<F> {
    extern "rust-call" fn call(&self, args: A) -> R {
        self.closure.call(args)
    }
}

unsafe extern fn block_context_dispose<B>(block: &mut B) {
    // Read the block onto the stack and let it drop
    ptr::read(block);
}

unsafe extern fn block_context_copy<B>(_dst: &mut B, _src: &B) {
    // The runtime memmoves the src block into the dst block, nothing to do
}

#[repr(C)]
struct BlockDescriptor<B> {
    _reserved: c_ulong,
    block_size: c_ulong,
    copy_helper: unsafe extern fn(&mut B, &B),
    dispose_helper: unsafe extern fn(&mut B),
}

impl<B> BlockDescriptor<B> {
    fn new() -> BlockDescriptor<B> {
        BlockDescriptor {
            _reserved: 0,
            block_size: mem::size_of::<B>() as c_ulong,
            copy_helper: block_context_copy::<B>,
            dispose_helper: block_context_dispose::<B>,
        }
    }
}

#[cfg(test)]
mod tests {
    use Id;
    use objc_test_utils;
    use super::{Block, ConcreteBlock};

    fn get_int_block() -> &'static Block<(), int> {
        unsafe {
            &*(objc_test_utils::get_int_block() as *const _)
        }
    }

    fn get_int_block_with(i: int) -> Id<Block<(), int>> {
        unsafe {
            let ptr = objc_test_utils::get_int_block_with(i);
            Id::from_retained_ptr(ptr as *mut _)
        }
    }

    fn get_add_block() -> &'static Block<(int,), int> {
        unsafe {
            &*(objc_test_utils::get_add_block() as *const _)
        }
    }

    fn get_add_block_with(i: int) -> Id<Block<(int,), int>> {
        unsafe {
            let ptr = objc_test_utils::get_add_block_with(i);
            Id::from_retained_ptr(ptr as *mut _)
        }
    }

    fn invoke_int_block(block: &Block<(), int>) -> int {
        let ptr = block as *const _;
        unsafe {
            objc_test_utils::invoke_int_block(ptr as *const _)
        }
    }

    fn invoke_add_block(block: &Block<(int,), int>, a: int) -> int {
        let ptr = block as *const _;
        unsafe {
            objc_test_utils::invoke_add_block(ptr as *const _, a)
        }
    }

    #[test]
    fn test_call_block() {
        let block = get_int_block();
        assert!((*block)() == 7);

        let block = get_int_block_with(13);
        assert!((*block)() == 13);
    }

    #[test]
    fn test_call_block_args() {
        let block = get_add_block();
        assert!((*block)(2) == 9);

        let block = get_add_block_with(13);
        assert!((*block)(2) == 15);
    }

    #[test]
    fn test_create_block() {
        let block = ConcreteBlock::new(|&:| 13);
        let result = invoke_int_block(&*block);
        assert!(result == 13);
    }

    #[test]
    fn test_create_block_args() {
        let block = ConcreteBlock::new(|&: a: int| a + 5);
        let result = invoke_add_block(&*block, 6);
        assert!(result == 11);
    }

    #[test]
    fn test_concrete_block_copy() {
        let s = String::from_str("Hello!");
        let expected_len = s.len();
        let block = ConcreteBlock::new(move |&:| s.len());
        assert!((*block)() == expected_len);

        let copied = block.copy();
        assert!((*copied)() == expected_len);
    }
}
<|endoftext|>