<commit_before>//! Deployments interface
extern crate serde_json;

use std::collections::HashMap;
use url::form_urlencoded;
use serde;

use self::super::{Github, Result};
use statuses::State;
use users::User;

/// Interface for repository deployements
pub struct Deployments<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
}

/// INterface for deployment statuses
pub struct DeploymentStatuses<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
    id: u64,
}

impl<'a> DeploymentStatuses<'a> {
    #[doc(hidden)]
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R, id: u64) -> DeploymentStatuses<'a>
    where
        O: Into<String>,
        R: Into<String>,
    {
        DeploymentStatuses {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            id: id,
        }
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/deployments/{}/statuses{}",
            self.owner,
            self.repo,
            self.id,
            more
        )
    }

    /// lists all statuses associated with a deployment
    pub fn list(&self) -> Result<Vec<DeploymentStatus>> {
        self.github.get::<Vec<DeploymentStatus>>(&self.path(""))
    }

    /// creates a new deployment status. For convenience, a DeploymentStatusOptions.builder
    /// interface is required for building up a request
    pub fn create(&self, status: &DeploymentStatusOptions) -> Result<DeploymentStatus> {
        let data = serde_json::to_string(&status)?;
        self.github.post::<DeploymentStatus>(
            &self.path(""),
            &data.as_bytes(),
        )
    }
}

impl<'a> Deployments<'a> {
    /// Create a new deployments instance
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R) -> Deployments<'a>
    where
        O: Into<String>,
        R: Into<String>,
    {
        Deployments {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/deployments{}", self.owner, self.repo, more)
    }

    /// lists all deployments for a repository
    pub fn list(&self, opts: &DeploymentListOptions) -> Result<Vec<Deployment>> {
        let mut uri = vec![self.path("")];
        if let Some(query) = opts.serialize() {
            uri.push(query);
        }
        self.github.get::<Vec<Deployment>>(&uri.join("?"))
    }

    /// creates a new deployment for this repository
    pub fn create(&self, dep: &DeploymentOptions) -> Result<Deployment> {
        let data = serde_json::to_string(&dep)?;
        self.github.post::<Deployment>(
            &self.path(""),
            data.as_bytes(),
        )
    }

    /// get a reference to the statuses api for a give deployment
    pub fn statuses(&self, id: u64) -> DeploymentStatuses {
        DeploymentStatuses::new(self.github, self.owner.as_str(), self.repo.as_str(), id)
    }
}

// representations

#[derive(Debug, Deserialize)]
pub struct Deployment {
    pub url: String,
    pub id: u64,
    pub sha: String,
    #[serde(rename = "ref")]
    pub commit_ref: String,
    pub task: String,
    pub payload: serde_json::Value,
    pub environment: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub creator: User,
    pub created_at: String,
    pub updated_at: String,
    pub statuses_url: String,
    pub repository_url: String,
}

#[derive(Debug, Serialize)]
pub struct DeploymentOptions {
    #[serde(rename = "ref")]
    pub commit_ref: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub task: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub auto_merge: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub required_contexts: Option<Vec<String>>,
    /// contents of payload should be valid JSON
    #[serde(skip_serializing_if = "Option::is_none")]
    pub payload: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub environment: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

impl DeploymentOptions {
    pub fn builder<C>(commit: C) -> DeploymentOptionsBuilder
    where
        C: Into<String>,
    {
        DeploymentOptionsBuilder::new(commit)
    }
}

#[derive(Default)]
pub struct DeploymentOptionsBuilder {
    pub commit_ref: String,
    pub task: Option<String>,
    pub auto_merge: Option<bool>,
    pub required_contexts: Option<Vec<String>>,
    pub payload: Option<String>,
    pub environment: Option<String>,
    pub description: Option<String>,
}

impl DeploymentOptionsBuilder {
    pub fn new<C>(commit: C) -> DeploymentOptionsBuilder
    where
        C: Into<String>,
    {
        DeploymentOptionsBuilder {
            commit_ref: commit.into(),
            ..Default::default()
        }
    }

    pub fn task<T>(&mut self, task: T) -> &mut DeploymentOptionsBuilder
    where
        T: Into<String>,
    {
        self.task = Some(task.into());
        self
    }

    pub fn auto_merge(&mut self, auto_merge: bool) -> &mut DeploymentOptionsBuilder {
        self.auto_merge = Some(auto_merge);
        self
    }

    pub fn required_contexts<C>(&mut self, ctxs: Vec<C>) -> &mut DeploymentOptionsBuilder
    where
        C: Into<String>,
    {
        self.required_contexts = Some(ctxs.into_iter().map(|c| c.into()).collect::<Vec<String>>());
        self
    }

    pub fn payload<T: serde::ser::Serialize>(&mut self, pl: T) -> &mut DeploymentOptionsBuilder {
        self.payload = serde_json::ser::to_string(&pl).ok();
        self
    }

    pub fn environment<E>(&mut self, env: E) -> &mut DeploymentOptionsBuilder
    where
        E: Into<String>,
    {
        self.environment = Some(env.into());
        self
    }

    pub fn description<D>(&mut self, desc: D) -> &mut DeploymentOptionsBuilder
    where
        D: Into<String>,
    {
        self.description = Some(desc.into());
        self
    }

    pub fn build(&self) -> DeploymentOptions {
        DeploymentOptions {
            commit_ref: self.commit_ref.clone(),
            task: self.task.clone(),
            auto_merge: self.auto_merge,
            required_contexts: self.required_contexts.clone(),
            payload: self.payload.clone(),
            environment: self.environment.clone(),
            description: self.description.clone(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct DeploymentStatus {
    pub url: String,
    pub created_at: String,
    pub updated_at: String,
    pub state: State,
    pub target_url: Option<String>,
    pub description: Option<String>,
    pub id: u64,
    pub deployment_url: String,
    pub repository_url: String,
    pub creator: User,
}

#[derive(Default)]
pub struct DeploymentStatusOptionsBuilder {
    state: State,
    target_url: Option<String>,
    description: Option<String>,
}

impl DeploymentStatusOptionsBuilder {
    pub fn new(state: State) -> DeploymentStatusOptionsBuilder {
        DeploymentStatusOptionsBuilder {
            state: state,
            ..Default::default()
        }
    }

    pub fn target_url<T>(&mut self, url: T) -> &mut DeploymentStatusOptionsBuilder
    where
        T: Into<String>,
    {
        self.target_url = Some(url.into());
        self
    }

    pub fn description<D>(&mut self, desc: D) -> &mut DeploymentStatusOptionsBuilder
    where
        D: Into<String>,
    {
        self.description = Some(desc.into());
        self
    }

    pub fn build(&self) -> DeploymentStatusOptions {
        DeploymentStatusOptions {
            state: self.state.clone(),
            target_url: self.target_url.clone(),
            description: self.description.clone(),
        }
    }
}

#[derive(Debug, Serialize)]
pub struct DeploymentStatusOptions {
    state: State,
    #[serde(skip_serializing_if = "Option::is_none")]
    target_url: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    description: Option<String>,
}

impl DeploymentStatusOptions {
    pub fn builder(state: State) -> DeploymentStatusOptionsBuilder {
        DeploymentStatusOptionsBuilder::new(state)
    }
}

#[derive(Default)]
pub struct DeploymentListOptions {
    params: HashMap<&'static str, String>,
}

impl DeploymentListOptions {
    /// return a new instance of a builder for options
    pub fn builder() -> DeploymentListOptionsBuilder {
        DeploymentListOptionsBuilder::new()
    }

    /// serialize options as a string. returns None if no options are defined
    pub fn serialize(&self) -> Option<String> {
        if self.params.is_empty() {
            None
        } else {
            let encoded: String = form_urlencoded::Serializer::new(String::new())
                .extend_pairs(&self.params)
                .finish();
            Some(encoded)
        }
    }
}

#[derive(Default)]
pub struct DeploymentListOptionsBuilder {
    params: HashMap<&'static str, String>,
}

impl DeploymentListOptionsBuilder {
    pub fn new() -> DeploymentListOptionsBuilder {
        DeploymentListOptionsBuilder { ..Default::default() }
    }

    pub fn sha<S>(&mut self, s: S) -> &mut DeploymentListOptionsBuilder
    where
        S: Into<String>,
    {
        self.params.insert("sha", s.into());
        self
    }

    pub fn commit_ref<G>(&mut self, r: G) -> &mut DeploymentListOptionsBuilder
    where
        G: Into<String>,
    {
        self.params.insert("ref", r.into());
        self
    }

    pub fn task<T>(&mut self, t: T) -> &mut DeploymentListOptionsBuilder
    where
        T: Into<String>,
    {
        self.params.insert("task", t.into());
        self
    }

    pub fn environment<E>(&mut self, e: E) -> &mut DeploymentListOptionsBuilder
    where
        E: Into<String>,
    {
        self.params.insert("environment", e.into());
        self
    }

    pub fn build(&self) -> DeploymentListOptions {
        DeploymentListOptions { params: self.params.clone() }
    }
}

#[cfg(test)]
mod tests {
    use super::{DeploymentStatusOptions, DeploymentOptions};
    use serde::ser::Serialize;
    use serde_json;
    use statuses::State;
    use std::collections::BTreeMap;

    fn test_encoding<E: Serialize>(tests: Vec<(E, &str)>) {
        for test in tests {
            match test {
                (k, v) => assert_eq!(serde_json::to_string(&k).unwrap(), v),
            }
        }
    }

    #[test]
    fn deployment_reqs() {
        let mut payload = BTreeMap::new();
        payload.insert("user", "atmos");
        payload.insert("room_id", "123456");
        let tests = vec![
            (
                DeploymentOptions::builder("test").build(),
                r#"{"ref":"test"}"#
            ),
            (
                DeploymentOptions::builder("test").task("launchit").build(),
                r#"{"ref":"test","task":"launchit"}"#
            ),
            (
                DeploymentOptions::builder("topic-branch")
                    .description("description")
                    .payload(payload)
                    .build(),
                r#"{"ref":"topic-branch","payload":"{\"room_id\":\"123456\",\"user\":\"atmos\"}","description":"description"}"#
            )
        ];
        test_encoding(tests)
    }

    #[test]
    fn deployment_status_reqs() {
        let tests = vec![
            (
                DeploymentStatusOptions::builder(State::Pending).build(),
                r#"{"state":"pending"}"#
            ),
            (
                DeploymentStatusOptions::builder(State::Pending)
                    .target_url("http://host.com")
                    .build(),
                r#"{"state":"pending","target_url":"http://host.com"}"#
            ),
            (
                DeploymentStatusOptions::builder(State::Pending)
                    .target_url("http://host.com")
                    .description("desc")
                    .build(),
                r#"{"state":"pending","target_url":"http://host.com","description":"desc"}"#
            ),
        ];
        test_encoding(tests)
    }
}
<commit_msg>Split an extra long (raw) string literal<commit_after>//! Deployments interface
extern crate serde_json;

use std::collections::HashMap;
use url::form_urlencoded;
use serde;

use self::super::{Github, Result};
use statuses::State;
use users::User;

/// Interface for repository deployements
pub struct Deployments<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
}

/// INterface for deployment statuses
pub struct DeploymentStatuses<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
    id: u64,
}

impl<'a> DeploymentStatuses<'a> {
    #[doc(hidden)]
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R, id: u64) -> DeploymentStatuses<'a>
    where
        O: Into<String>,
        R: Into<String>,
    {
        DeploymentStatuses {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            id: id,
        }
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/deployments/{}/statuses{}",
            self.owner,
            self.repo,
            self.id,
            more
        )
    }

    /// lists all statuses associated with a deployment
    pub fn list(&self) -> Result<Vec<DeploymentStatus>> {
        self.github.get::<Vec<DeploymentStatus>>(&self.path(""))
    }

    /// creates a new deployment status. For convenience, a DeploymentStatusOptions.builder
    /// interface is required for building up a request
    pub fn create(&self, status: &DeploymentStatusOptions) -> Result<DeploymentStatus> {
        let data = serde_json::to_string(&status)?;
        self.github.post::<DeploymentStatus>(
            &self.path(""),
            &data.as_bytes(),
        )
    }
}

impl<'a> Deployments<'a> {
    /// Create a new deployments instance
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R) -> Deployments<'a>
    where
        O: Into<String>,
        R: Into<String>,
    {
        Deployments {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/deployments{}", self.owner, self.repo, more)
    }

    /// lists all deployments for a repository
    pub fn list(&self, opts: &DeploymentListOptions) -> Result<Vec<Deployment>> {
        let mut uri = vec![self.path("")];
        if let Some(query) = opts.serialize() {
            uri.push(query);
        }
        self.github.get::<Vec<Deployment>>(&uri.join("?"))
    }

    /// creates a new deployment for this repository
    pub fn create(&self, dep: &DeploymentOptions) -> Result<Deployment> {
        let data = serde_json::to_string(&dep)?;
        self.github.post::<Deployment>(
            &self.path(""),
            data.as_bytes(),
        )
    }

    /// get a reference to the statuses api for a give deployment
    pub fn statuses(&self, id: u64) -> DeploymentStatuses {
        DeploymentStatuses::new(self.github, self.owner.as_str(), self.repo.as_str(), id)
    }
}

// representations

#[derive(Debug, Deserialize)]
pub struct Deployment {
    pub url: String,
    pub id: u64,
    pub sha: String,
    #[serde(rename = "ref")]
    pub commit_ref: String,
    pub task: String,
    pub payload: serde_json::Value,
    pub environment: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub creator: User,
    pub created_at: String,
    pub updated_at: String,
    pub statuses_url: String,
    pub repository_url: String,
}

#[derive(Debug, Serialize)]
pub struct DeploymentOptions {
    #[serde(rename = "ref")]
    pub commit_ref: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub task: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub auto_merge: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub required_contexts: Option<Vec<String>>,
    /// contents of payload should be valid JSON
    #[serde(skip_serializing_if = "Option::is_none")]
    pub payload: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub environment: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

impl DeploymentOptions {
    pub fn builder<C>(commit: C) -> DeploymentOptionsBuilder
    where
        C: Into<String>,
    {
        DeploymentOptionsBuilder::new(commit)
    }
}

#[derive(Default)]
pub struct DeploymentOptionsBuilder {
    pub commit_ref: String,
    pub task: Option<String>,
    pub auto_merge: Option<bool>,
    pub required_contexts: Option<Vec<String>>,
    pub payload: Option<String>,
    pub environment: Option<String>,
    pub description: Option<String>,
}

impl DeploymentOptionsBuilder {
    pub fn new<C>(commit: C) -> DeploymentOptionsBuilder
    where
        C: Into<String>,
    {
        DeploymentOptionsBuilder {
            commit_ref: commit.into(),
            ..Default::default()
        }
    }

    pub fn task<T>(&mut self, task: T) -> &mut DeploymentOptionsBuilder
    where
        T: Into<String>,
    {
        self.task = Some(task.into());
        self
    }

    pub fn auto_merge(&mut self, auto_merge: bool) -> &mut DeploymentOptionsBuilder {
        self.auto_merge = Some(auto_merge);
        self
    }

    pub fn required_contexts<C>(&mut self, ctxs: Vec<C>) -> &mut DeploymentOptionsBuilder
    where
        C: Into<String>,
    {
        self.required_contexts = Some(ctxs.into_iter().map(|c| c.into()).collect::<Vec<String>>());
        self
    }

    pub fn payload<T: serde::ser::Serialize>(&mut self, pl: T) -> &mut DeploymentOptionsBuilder {
        self.payload = serde_json::ser::to_string(&pl).ok();
        self
    }

    pub fn environment<E>(&mut self, env: E) -> &mut DeploymentOptionsBuilder
    where
        E: Into<String>,
    {
        self.environment = Some(env.into());
        self
    }

    pub fn description<D>(&mut self, desc: D) -> &mut DeploymentOptionsBuilder
    where
        D: Into<String>,
    {
        self.description = Some(desc.into());
        self
    }

    pub fn build(&self) -> DeploymentOptions {
        DeploymentOptions {
            commit_ref: self.commit_ref.clone(),
            task: self.task.clone(),
            auto_merge: self.auto_merge,
            required_contexts: self.required_contexts.clone(),
            payload: self.payload.clone(),
            environment: self.environment.clone(),
            description: self.description.clone(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct DeploymentStatus {
    pub url: String,
    pub created_at: String,
    pub updated_at: String,
    pub state: State,
    pub target_url: Option<String>,
    pub description: Option<String>,
    pub id: u64,
    pub deployment_url: String,
    pub repository_url: String,
    pub creator: User,
}

#[derive(Default)]
pub struct DeploymentStatusOptionsBuilder {
    state: State,
    target_url: Option<String>,
    description: Option<String>,
}

impl DeploymentStatusOptionsBuilder {
    pub fn new(state: State) -> DeploymentStatusOptionsBuilder {
        DeploymentStatusOptionsBuilder {
            state: state,
            ..Default::default()
        }
    }

    pub fn target_url<T>(&mut self, url: T) -> &mut DeploymentStatusOptionsBuilder
    where
        T: Into<String>,
    {
        self.target_url = Some(url.into());
        self
    }

    pub fn description<D>(&mut self, desc: D) -> &mut DeploymentStatusOptionsBuilder
    where
        D: Into<String>,
    {
        self.description = Some(desc.into());
        self
    }

    pub fn build(&self) -> DeploymentStatusOptions {
        DeploymentStatusOptions {
            state: self.state.clone(),
            target_url: self.target_url.clone(),
            description: self.description.clone(),
        }
    }
}

#[derive(Debug, Serialize)]
pub struct DeploymentStatusOptions {
    state: State,
    #[serde(skip_serializing_if = "Option::is_none")]
    target_url: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    description: Option<String>,
}

impl DeploymentStatusOptions {
    pub fn builder(state: State) -> DeploymentStatusOptionsBuilder {
        DeploymentStatusOptionsBuilder::new(state)
    }
}

#[derive(Default)]
pub struct DeploymentListOptions {
    params: HashMap<&'static str, String>,
}

impl DeploymentListOptions {
    /// return a new instance of a builder for options
    pub fn builder() -> DeploymentListOptionsBuilder {
        DeploymentListOptionsBuilder::new()
    }

    /// serialize options as a string. returns None if no options are defined
    pub fn serialize(&self) -> Option<String> {
        if self.params.is_empty() {
            None
        } else {
            let encoded: String = form_urlencoded::Serializer::new(String::new())
                .extend_pairs(&self.params)
                .finish();
            Some(encoded)
        }
    }
}

#[derive(Default)]
pub struct DeploymentListOptionsBuilder {
    params: HashMap<&'static str, String>,
}

impl DeploymentListOptionsBuilder {
    pub fn new() -> DeploymentListOptionsBuilder {
        DeploymentListOptionsBuilder { ..Default::default() }
    }

    pub fn sha<S>(&mut self, s: S) -> &mut DeploymentListOptionsBuilder
    where
        S: Into<String>,
    {
        self.params.insert("sha", s.into());
        self
    }

    pub fn commit_ref<G>(&mut self, r: G) -> &mut DeploymentListOptionsBuilder
    where
        G: Into<String>,
    {
        self.params.insert("ref", r.into());
        self
    }

    pub fn task<T>(&mut self, t: T) -> &mut DeploymentListOptionsBuilder
    where
        T: Into<String>,
    {
        self.params.insert("task", t.into());
        self
    }

    pub fn environment<E>(&mut self, e: E) -> &mut DeploymentListOptionsBuilder
    where
        E: Into<String>,
    {
        self.params.insert("environment", e.into());
        self
    }

    pub fn build(&self) -> DeploymentListOptions {
        DeploymentListOptions { params: self.params.clone() }
    }
}

#[cfg(test)]
mod tests {
    use super::{DeploymentStatusOptions, DeploymentOptions};
    use serde::ser::Serialize;
    use serde_json;
    use statuses::State;
    use std::collections::BTreeMap;

    fn test_encoding<E: Serialize>(tests: Vec<(E, &str)>) {
        for test in tests {
            match test {
                (k, v) => assert_eq!(serde_json::to_string(&k).unwrap(), v),
            }
        }
    }

    #[test]
    fn deployment_reqs() {
        let mut payload = BTreeMap::new();
        payload.insert("user", "atmos");
        payload.insert("room_id", "123456");
        let tests = vec![
            (
                DeploymentOptions::builder("test").build(),
                r#"{"ref":"test"}"#
            ),
            (
                DeploymentOptions::builder("test").task("launchit").build(),
                r#"{"ref":"test","task":"launchit"}"#
            ),
            (
                DeploymentOptions::builder("topic-branch")
                    .description("description")
                    .payload(payload)
                    .build(),
                concat!(
                    "{",
                    r#""ref":"topic-branch","#,
                    r#""payload":"{\"room_id\":\"123456\",\"user\":\"atmos\"}","#,
                    r#""description":"description""#,
                    "}"
                )
            )
        ];
        test_encoding(tests)
    }

    #[test]
    fn deployment_status_reqs() {
        let tests = vec![
            (
                DeploymentStatusOptions::builder(State::Pending).build(),
                r#"{"state":"pending"}"#
            ),
            (
                DeploymentStatusOptions::builder(State::Pending)
                    .target_url("http://host.com")
                    .build(),
                r#"{"state":"pending","target_url":"http://host.com"}"#
            ),
            (
                DeploymentStatusOptions::builder(State::Pending)
                    .target_url("http://host.com")
                    .description("desc")
                    .build(),
                r#"{"state":"pending","target_url":"http://host.com","description":"desc"}"#
            ),
        ];
        test_encoding(tests)
    }
}
<|endoftext|>


<commit_before>//! A very simple wrapper for LLVM that can JIT functions written as IR strings.

extern crate llvm_sys as llvm;

use std::error::Error;
use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::result::Result;
use std::ops::Drop;
use std::os::raw::c_char;
use std::sync::{Once, ONCE_INIT};

use llvm::execution_engine::LLVMMCJITCompilerOptions;
use llvm::analysis::LLVMVerifierFailureAction;
use llvm::transforms::pass_manager_builder;

#[cfg(test)]
mod tests;

static ONCE: Once = ONCE_INIT;
static mut initialize_failed: bool = false;

/// Error type returned by easy_ll.
#[derive(Debug)]
pub struct LlvmError(String);

impl LlvmError {
    fn new(description: &str) -> LlvmError { LlvmError(description.to_string()) }
}

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

impl Error for LlvmError {
    fn description(&self) -> &str { &self.0 }

    fn cause(&self) -> Option<&Error> { None }
}

impl From<NulError> for LlvmError {
    fn from(_: NulError) -> LlvmError { LlvmError::new("Null byte in string") }
}

/// A compiled module returned by `compile_module`, wrapping a `run` function that takes `u64`
/// and returns `u64`. This structure includes (and manages) an LLVM execution engine, which is
/// freed when this structure is dropped.
#[derive(Debug)]
pub struct CompiledModule {
    context: llvm::prelude::LLVMContextRef,
    engine: Option<llvm::execution_engine::LLVMExecutionEngineRef>,
    function: Option<extern "C" fn(u64) -> u64>
}

impl CompiledModule {
    /// Call the module's `run` function.
    pub fn run(&self, arg: u64) -> u64 {
        (self.function.unwrap())(arg)
    }
}

impl Drop for CompiledModule {
    /// Disposes of the LLVM execution engine and compiled function.
    fn drop(&mut self) {
        unsafe {
            self.engine.map(|e| {
                llvm::execution_engine::LLVMDisposeExecutionEngine(e)
            });
            llvm::core::LLVMContextDispose(self.context);
        }
    }
}

/// Initialize LLVM or save an error message in `initialize_failed` if this does not work.
/// We call this function only once in cases some steps are expensive.
fn initialize() {
    unsafe {
        if llvm::target::LLVM_InitializeNativeTarget() != 0 {
            initialize_failed = true;
            return;
        }
        if llvm::target::LLVM_InitializeNativeAsmPrinter() != 0 {
            initialize_failed = true;
            return;
        }
        if llvm::target::LLVM_InitializeNativeAsmParser() != 0 {
            initialize_failed = true;
            return;
        }
        llvm::execution_engine::LLVMLinkInMCJIT();
    }
}

/// Compile a string of LLVM IR (in human readable format) into a `CompiledModule` that can then
/// be executed. The LLVM IR should contain an entry point function called `run` that takes `i64`
/// and returns `i64`, which will be called by `CompiledModule::run`.
pub fn compile_module(code: &str) -> Result<CompiledModule, LlvmError> {
    unsafe {
        // Initialize LLVM
        ONCE.call_once(|| initialize());
        if initialize_failed {
            return Err(LlvmError::new("LLVM initialization failed"))
        }

        // Create an LLVM context
        let context = llvm::core::LLVMContextCreate();
        if context.is_null() {
            return Err(LlvmError::new("LLVMContextCreate returned null"))
        }

        // Create a module
        let mut result = CompiledModule { context: context, engine: None, function: None };

        // Create a memory buffer to hold the code
        let code_len = code.len();
        let name = try!(CString::new("module"));
        let code = try!(CString::new(code));
        let buffer = llvm::core::LLVMCreateMemoryBufferWithMemoryRange(
            code.as_ptr(), code_len, name.as_ptr(), 0);
        if buffer.is_null() {
            return Err(LlvmError::new("LLVMCreateMemoryBufferWithMemoryRange failed"))
        }

        // Parse IR into a module
        let mut module = 0 as llvm::prelude::LLVMModuleRef;
        let mut error_str = 0 as *mut c_char;
        let result_code = llvm::ir_reader::LLVMParseIRInContext(
            context, buffer, &mut module, &mut error_str);
        if result_code != 0 {
            let msg = format!("Compile error: {}", CStr::from_ptr(error_str).to_str().unwrap());
            return Err(LlvmError(msg));
        }

        // Verify module
        let mut error_str = 0 as *mut c_char;
        let result_code = llvm::analysis::LLVMVerifyModule(
            module, LLVMVerifierFailureAction::LLVMReturnStatusAction, &mut error_str);
        if result_code != 0 {
            let msg = format!("Module verification failed: {}",
                CStr::from_ptr(error_str).to_str().unwrap());
            return Err(LlvmError(msg));
        }

        // Optimize module
        let manager = llvm::core::LLVMCreatePassManager();
        if manager.is_null() {
            return Err(LlvmError::new("LLVMCreatePassManager returned null"))
        }
        let builder = pass_manager_builder::LLVMPassManagerBuilderCreate();
        if builder.is_null() {
            return Err(LlvmError::new("LLVMPassManagerBuilderCreate returned null"))
        }
        pass_manager_builder::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, manager);
        pass_manager_builder::LLVMPassManagerBuilderPopulateModulePassManager(builder, manager);
        pass_manager_builder::LLVMPassManagerBuilderPopulateLTOPassManager(builder, manager, 1, 1);
        pass_manager_builder::LLVMPassManagerBuilderDispose(builder);
        llvm::core::LLVMRunPassManager(manager, module);
        llvm::core::LLVMDisposePassManager(manager);

        // Create an execution engine
        let mut engine = 0 as llvm::execution_engine::LLVMExecutionEngineRef;
        let mut error_str = 0 as *mut c_char;
        let mut options: LLVMMCJITCompilerOptions = std::mem::uninitialized();
        options.OptLevel = 2;
        let options_size = std::mem::size_of::<LLVMMCJITCompilerOptions>();
        llvm::execution_engine::LLVMInitializeMCJITCompilerOptions(&mut options, options_size);
        let result_code = llvm::execution_engine::LLVMCreateMCJITCompilerForModule(
            &mut engine, module, &mut options, options_size, &mut error_str);
        if result_code != 0 {
            let msg = format!("Creating execution engine failed: {}",
                CStr::from_ptr(error_str).to_str().unwrap());
            return Err(LlvmError(msg));
        }
        result.engine = Some(engine);

        // Find the "run" function
        let func_address = llvm::execution_engine::LLVMGetFunctionAddress(
            engine, CString::new("run").unwrap().into_raw());
        if func_address == 0 {
            return Err(LlvmError::new("No run function in module"))
        }
        let func: extern fn(u64) -> u64 = std::mem::transmute(func_address);
        result.function = Some(func);

        Ok(result)
    }
}<commit_msg>Tweaks<commit_after>//! A very simple wrapper for LLVM that can JIT functions written as IR strings.

extern crate llvm_sys as llvm;

use std::error::Error;
use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::result::Result;
use std::ops::Drop;
use std::os::raw::c_char;
use std::sync::{Once, ONCE_INIT};

use llvm::execution_engine::LLVMMCJITCompilerOptions;
use llvm::analysis::LLVMVerifierFailureAction;
use llvm::transforms::pass_manager_builder as pmb;

#[cfg(test)]
mod tests;

static ONCE: Once = ONCE_INIT;
static mut initialize_failed: bool = false;

/// Error type returned by easy_ll.
#[derive(Debug)]
pub struct LlvmError(String);

impl LlvmError {
    fn new(description: &str) -> LlvmError { LlvmError(description.to_string()) }
}

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

impl Error for LlvmError {
    fn description(&self) -> &str { &self.0 }

    fn cause(&self) -> Option<&Error> { None }
}

impl From<NulError> for LlvmError {
    fn from(_: NulError) -> LlvmError { LlvmError::new("Null byte in string") }
}

/// A compiled module returned by `compile_module`, wrapping a `run` function that takes `u64`
/// and returns `u64`. This structure includes (and manages) an LLVM execution engine, which is
/// freed when this structure is dropped.
#[derive(Debug)]
pub struct CompiledModule {
    context: llvm::prelude::LLVMContextRef,
    engine: Option<llvm::execution_engine::LLVMExecutionEngineRef>,
    function: Option<extern "C" fn(u64) -> u64>
}

impl CompiledModule {
    /// Call the module's `run` function.
    pub fn run(&self, arg: u64) -> u64 {
        (self.function.unwrap())(arg)
    }
}

impl Drop for CompiledModule {
    /// Disposes of the LLVM execution engine and compiled function.
    fn drop(&mut self) {
        unsafe {
            self.engine.map(|e| {
                llvm::execution_engine::LLVMDisposeExecutionEngine(e)
            });
            llvm::core::LLVMContextDispose(self.context);
        }
    }
}

/// Initialize LLVM or save an error message in `initialize_failed` if this does not work.
/// We call this function only once in cases some steps are expensive.
fn initialize() {
    unsafe {
        if llvm::target::LLVM_InitializeNativeTarget() != 0 {
            initialize_failed = true;
            return;
        }
        if llvm::target::LLVM_InitializeNativeAsmPrinter() != 0 {
            initialize_failed = true;
            return;
        }
        if llvm::target::LLVM_InitializeNativeAsmParser() != 0 {
            initialize_failed = true;
            return;
        }
        llvm::execution_engine::LLVMLinkInMCJIT();
    }
}

/// Compile a string of LLVM IR (in human readable format) into a `CompiledModule` that can then
/// be executed. The LLVM IR should contain an entry point function called `run` that takes `i64`
/// and returns `i64`, which will be called by `CompiledModule::run`.
pub fn compile_module(code: &str) -> Result<CompiledModule, LlvmError> {
    unsafe {
        // Initialize LLVM
        ONCE.call_once(|| initialize());
        if initialize_failed {
            return Err(LlvmError::new("LLVM initialization failed"))
        }

        // Create an LLVM context
        let context = llvm::core::LLVMContextCreate();
        if context.is_null() {
            return Err(LlvmError::new("LLVMContextCreate returned null"))
        }

        // Create a module
        let mut result = CompiledModule { context: context, engine: None, function: None };

        // Create a memory buffer to hold the code
        let code_len = code.len();
        let name = try!(CString::new("module"));
        let code = try!(CString::new(code));
        let buffer = llvm::core::LLVMCreateMemoryBufferWithMemoryRange(
            code.as_ptr(), code_len, name.as_ptr(), 0);
        if buffer.is_null() {
            return Err(LlvmError::new("LLVMCreateMemoryBufferWithMemoryRange failed"))
        }

        // Parse IR into a module
        let mut module = 0 as llvm::prelude::LLVMModuleRef;
        let mut error_str = 0 as *mut c_char;
        let result_code = llvm::ir_reader::LLVMParseIRInContext(
            context, buffer, &mut module, &mut error_str);
        if result_code != 0 {
            let msg = format!("Compile error: {}", CStr::from_ptr(error_str).to_str().unwrap());
            return Err(LlvmError(msg));
        }

        // Verify module
        let mut error_str = 0 as *mut c_char;
        let result_code = llvm::analysis::LLVMVerifyModule(
            module, LLVMVerifierFailureAction::LLVMReturnStatusAction, &mut error_str);
        if result_code != 0 {
            let msg = format!("Module verification failed: {}",
                CStr::from_ptr(error_str).to_str().unwrap());
            return Err(LlvmError(msg));
        }

        // TODO: check type of run() function in module!

        // Optimize module
        let manager = llvm::core::LLVMCreatePassManager();
        if manager.is_null() {
            return Err(LlvmError::new("LLVMCreatePassManager returned null"))
        }
        let builder = pmb::LLVMPassManagerBuilderCreate();
        if builder.is_null() {
            return Err(LlvmError::new("LLVMPassManagerBuilderCreate returned null"))
        }
        pmb::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, manager);
        pmb::LLVMPassManagerBuilderPopulateModulePassManager(builder, manager);
        pmb::LLVMPassManagerBuilderPopulateLTOPassManager(builder, manager, 1, 1);
        pmb::LLVMPassManagerBuilderDispose(builder);
        llvm::core::LLVMRunPassManager(manager, module);
        llvm::core::LLVMDisposePassManager(manager);

        // Create an execution engine
        let mut engine = 0 as llvm::execution_engine::LLVMExecutionEngineRef;
        let mut error_str = 0 as *mut c_char;
        let mut options: LLVMMCJITCompilerOptions = std::mem::uninitialized();
        options.OptLevel = 2;
        let options_size = std::mem::size_of::<LLVMMCJITCompilerOptions>();
        llvm::execution_engine::LLVMInitializeMCJITCompilerOptions(&mut options, options_size);
        let result_code = llvm::execution_engine::LLVMCreateMCJITCompilerForModule(
            &mut engine, module, &mut options, options_size, &mut error_str);
        if result_code != 0 {
            let msg = format!("Creating execution engine failed: {}",
                CStr::from_ptr(error_str).to_str().unwrap());
            return Err(LlvmError(msg));
        }
        result.engine = Some(engine);

        // Find the "run" function
        let func_address = llvm::execution_engine::LLVMGetFunctionAddress(
            engine, CString::new("run").unwrap().as_ptr());
        if func_address == 0 {
            return Err(LlvmError::new("No run function in module"))
        }
        let func: extern fn(u64) -> u64 = std::mem::transmute(func_address);
        result.function = Some(func);

        Ok(result)
    }
}<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    key:    u8,
    mem:    [u8; 4096],
    stack:  Vec<u16>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0x200,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            key:    0,
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        println!("i: {}", self.i);

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }

        // TODO: refactor this to self.screen.present();
        self.screen.renderer.present();
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr);
    }

    fn jmp(&mut self) {
        let addr: u16 = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr: u16 = self.pc as u16;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] += self.regs[idx_y];
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        self.i += self.regs[idx] as u16;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };
        self.regs[idx_x] -= y;
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let vx    = self.regs[idx_x];
        if vx & 0x01 == 0 {
            self.regs[15] = 1;
        }
        self.regs[idx_x] = vx >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let mut vx  = self.regs[idx];
        let mut hundred = 100;

        for i in 0usize..3 {
            let bcd = vx / hundred;
            self.mem[self.i as usize + i] = bcd;
            vx -= bcd * hundred;
            hundred /= 10;
        }
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.regs[self.inst.x] as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.regs[self.inst.x] as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        let start = self.i;

        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(start + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..320 {
            for j in 0usize..640 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if x == self.key {
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if x != self.key {
            self.inc_pc();
        }
    }
}
<commit_msg>changed stack values' type to usize<commit_after>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    key:    u8,
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0x200,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            key:    0,
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        println!("i: {}", self.i);

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }

        // TODO: refactor this to self.screen.present();
        self.screen.renderer.present();
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] += self.regs[idx_y];
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        self.i += self.regs[idx] as u16;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };
        self.regs[idx_x] -= y;
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let vx    = self.regs[idx_x];
        if vx & 0x01 == 0 {
            self.regs[15] = 1;
        }
        self.regs[idx_x] = vx >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let mut vx  = self.regs[idx];
        let mut hundred = 100;

        for i in 0usize..3 {
            let bcd = vx / hundred;
            self.mem[self.i as usize + i] = bcd;
            vx -= bcd * hundred;
            hundred /= 10;
        }
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.regs[self.inst.x] as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.regs[self.inst.x] as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        let start = self.i;

        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(start + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..320 {
            for j in 0usize..640 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if x == self.key {
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if x != self.key {
            self.inc_pc();
        }
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;
use std::io;

use util::*;
use error::ClassResult;
use attr::Attributes;
use constant_pool::ConstantPool;
use field::Fields;
use method::Methods;

pub const ACC_PUBLIC: u16       = 0x0001;
pub const ACC_PRIVATE: u16      = 0x0002;
pub const ACC_PROTECTED: u16    = 0x0004;
pub const ACC_STATIC: u16       = 0x0008;
pub const ACC_FINAL: u16        = 0x0010;
pub const ACC_SUPER: u16        = 0x0020;
pub const ACC_VOLATILE: u16     = 0x0040;
pub const ACC_TRANSIENT: u16    = 0x0080;
pub const ACC_INTERFACE: u16    = 0x0200;
pub const ACC_ABSTRACT: u16     = 0x0400;
pub const ACC_SYNTHETIC: u16    = 0x1000;
pub const ACC_ANNOTATION: u16   = 0x1000;
pub const ACC_ENUM: u16         = 0x4000;

#[derive(Debug)]
pub struct ClassFile {
    pub magic: u32,
    pub minor_version: u16,
    pub major_version: u16,
    pub constant_pool: ConstantPool,
    pub access_flags: u16,
    pub this_class: u16,
    pub super_class: u16,
    pub interfaces: Vec<u16>,
    pub fields: Fields,
    pub methods: Methods,
    pub attributes: Attributes
}

impl ClassFile {
    pub fn read<T: io::Read>(rdr: &mut T) -> ClassResult<ClassFile> {
        let magic = try!(read_u32(rdr));
        let minor_version = try!(read_u16(rdr));
        let major_version = try!(read_u16(rdr));
        let constant_pool = try!(ConstantPool::read(rdr));
        let access_flags = try!(read_u16(rdr));
        let this_class = try!(read_u16(rdr));
        let super_class = try!(read_u16(rdr));
        let interfaces_count = try!(read_u16(rdr));
        let mut interfaces: Vec<u16> = vec![];
        for _ in 0..interfaces_count {
            let entry = try!(read_u16(rdr));
            interfaces.push(entry);
        }
        let fields = try!(Fields::read(rdr));
        let methods = try!(Methods::read(rdr));
        let attributes = try!(Attributes::read(rdr));
        Ok(ClassFile {
            magic: magic,
            minor_version: minor_version,
            major_version: major_version,
            constant_pool: constant_pool,
            access_flags: access_flags,
            this_class: this_class,
            super_class: super_class,
            interfaces: interfaces,
            fields: fields,
            methods: methods,
            attributes: attributes
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::File;

    use constant_pool::ConstantPoolTag;

    #[test]
    fn test_load_hello_world_class() {
        // Given
        let mut file = File::open("test-classes/HelloWorld.class").unwrap();

        // When
        let classfile = ClassFile::read(&mut file).unwrap();

        // Then
        assert_eq!(0xcafebabe, classfile.magic);
        assert_eq!(52, classfile.major_version);
        assert_eq!(0, classfile.minor_version);
        assert_eq!(29, classfile.constant_pool.len());
        assert_eq!(
            ACC_PUBLIC | ACC_SUPER,
            classfile.access_flags);

        // Constant pool entries
        assert_eq!(
            ConstantPoolTag::Methodref {
                class_index: 6,
                name_and_type_index: 15
            },
            classfile.constant_pool[1]);
        assert_eq!(
            ConstantPoolTag::Fieldref {
                class_index: 16,
                name_and_type_index: 17
            },
            classfile.constant_pool[2]);
        assert_eq!(
            ConstantPoolTag::String {
                string_index: 18
            },
            classfile.constant_pool[3]);
        assert_eq!(
            ConstantPoolTag::Methodref {
                class_index: 19,
                name_and_type_index: 20
            },
            classfile.constant_pool[4]);
        assert_eq!(
            ConstantPoolTag::Class {
                name_index: 21
            },
            classfile.constant_pool[5]);
        assert_eq!(
            ConstantPoolTag::Class {
                name_index: 22
            },
            classfile.constant_pool[6]);
        assert_utf8_tag(
            "<init>",
            &classfile.constant_pool[7]);
        assert_utf8_tag(
            "()V",
            &classfile.constant_pool[8]);
        assert_utf8_tag(
            "Code",
            &classfile.constant_pool[9]);
        assert_utf8_tag(
            "LineNumberTable",
            &classfile.constant_pool[10]);
        assert_utf8_tag(
            "main",
            &classfile.constant_pool[11]);
        assert_utf8_tag(
            "([Ljava/lang/String;)V",
            &classfile.constant_pool[12]);
        assert_utf8_tag(
            "SourceFile",
            &classfile.constant_pool[13]);
        assert_utf8_tag(
            "HelloWorld.java",
            &classfile.constant_pool[14]);
        assert_eq!(
            ConstantPoolTag::NameAndType {
                name_index: 7,
                descriptor_index: 8
            },
            classfile.constant_pool[15]);
        assert_eq!(
            ConstantPoolTag::Class {
                name_index: 23
            },
            classfile.constant_pool[16]);
        assert_eq!(
            ConstantPoolTag::NameAndType {
                name_index: 24,
                descriptor_index: 25
            },
            classfile.constant_pool[17]);
        assert_utf8_tag(
            "Hello World!",
            &classfile.constant_pool[18]);
        assert_eq!(
            ConstantPoolTag::Class {
                name_index: 26
            },
            classfile.constant_pool[19]);
        assert_eq!(
            ConstantPoolTag::NameAndType {
                name_index: 27,
                descriptor_index: 28
            },
            classfile.constant_pool[20]);
        assert_utf8_tag(
            "io/hcf/frappe/HelloWorld",
            &classfile.constant_pool[21]);
        assert_utf8_tag(
            "java/lang/Object",
            &classfile.constant_pool[22]);
        assert_utf8_tag(
            "java/lang/System",
            &classfile.constant_pool[23]);
        assert_utf8_tag(
            "out",
            &classfile.constant_pool[24]);
        assert_utf8_tag(
            "Ljava/io/PrintStream;",
            &classfile.constant_pool[25]);
        assert_utf8_tag(
            "java/io/PrintStream",
            &classfile.constant_pool[26]);
        assert_utf8_tag(
            "println",
            &classfile.constant_pool[27]);
        assert_utf8_tag(
            "(Ljava/lang/String;)V",
            &classfile.constant_pool[28]);

        assert_eq!(0, classfile.fields.len());
        assert_eq!(0, classfile.fields.len());

        // 2 methods
        assert_eq!(2, classfile.methods.len());
        // ctor
        let ctor_info = &classfile.methods[0];
        assert_eq!(
            ACC_PUBLIC,
            ctor_info.access_flags);
        assert_utf8_tag(
            "<init>",
            &classfile.constant_pool[ctor_info.name_index]);
        assert_utf8_tag(
            "()V",
            &classfile.constant_pool[ctor_info.descriptor_index]);
        // main
        let main_info = &classfile.methods[1];
        assert_eq!(
            ACC_PUBLIC | ACC_STATIC,
            main_info.access_flags);
        assert_utf8_tag(
            "main",
            &classfile.constant_pool[main_info.name_index]);
        assert_utf8_tag(
            "([Ljava/lang/String;)V",
            &classfile.constant_pool[main_info.descriptor_index]);

        // 1 attribute
        assert_eq!(1, classfile.attributes.len());
    }

    fn assert_utf8_tag(value: &str, tag: &ConstantPoolTag) {
        let expected_tag = ConstantPoolTag::Utf8(value.into());
        assert_eq!(expected_tag, *tag);
    }
}

<commit_msg>Fix test.<commit_after>use std::vec::Vec;
use std::io;

use util::*;
use error::ClassResult;
use attr::Attributes;
use constant_pool::ConstantPool;
use field::Fields;
use method::Methods;

pub const ACC_PUBLIC: u16       = 0x0001;
pub const ACC_PRIVATE: u16      = 0x0002;
pub const ACC_PROTECTED: u16    = 0x0004;
pub const ACC_STATIC: u16       = 0x0008;
pub const ACC_FINAL: u16        = 0x0010;
pub const ACC_SUPER: u16        = 0x0020;
pub const ACC_VOLATILE: u16     = 0x0040;
pub const ACC_TRANSIENT: u16    = 0x0080;
pub const ACC_INTERFACE: u16    = 0x0200;
pub const ACC_ABSTRACT: u16     = 0x0400;
pub const ACC_SYNTHETIC: u16    = 0x1000;
pub const ACC_ANNOTATION: u16   = 0x1000;
pub const ACC_ENUM: u16         = 0x4000;

#[derive(Debug)]
pub struct ClassFile {
    pub magic: u32,
    pub minor_version: u16,
    pub major_version: u16,
    pub constant_pool: ConstantPool,
    pub access_flags: u16,
    pub this_class: u16,
    pub super_class: u16,
    pub interfaces: Vec<u16>,
    pub fields: Fields,
    pub methods: Methods,
    pub attributes: Attributes
}

impl ClassFile {
    pub fn read<T: io::Read>(rdr: &mut T) -> ClassResult<ClassFile> {
        let magic = try!(read_u32(rdr));
        let minor_version = try!(read_u16(rdr));
        let major_version = try!(read_u16(rdr));
        let constant_pool = try!(ConstantPool::read(rdr));
        let access_flags = try!(read_u16(rdr));
        let this_class = try!(read_u16(rdr));
        let super_class = try!(read_u16(rdr));
        let interfaces_count = try!(read_u16(rdr));
        let mut interfaces: Vec<u16> = vec![];
        for _ in 0..interfaces_count {
            let entry = try!(read_u16(rdr));
            interfaces.push(entry);
        }
        let fields = try!(Fields::read(rdr));
        let methods = try!(Methods::read(rdr));
        let attributes = try!(Attributes::read(rdr));
        Ok(ClassFile {
            magic: magic,
            minor_version: minor_version,
            major_version: major_version,
            constant_pool: constant_pool,
            access_flags: access_flags,
            this_class: this_class,
            super_class: super_class,
            interfaces: interfaces,
            fields: fields,
            methods: methods,
            attributes: attributes
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::File;

    use constant_pool::Tag;

    #[test]
    fn test_load_hello_world_class() {
        // Given
        let mut file = File::open("test-classes/HelloWorld.class").unwrap();

        // When
        let classfile = ClassFile::read(&mut file).unwrap();

        // Then
        assert_eq!(0xcafebabe, classfile.magic);
        assert_eq!(52, classfile.major_version);
        assert_eq!(0, classfile.minor_version);
        assert_eq!(29, classfile.constant_pool.len());
        assert_eq!(
            ACC_PUBLIC | ACC_SUPER,
            classfile.access_flags);

        // Constant pool entries
        assert_eq!(
            Tag::Methodref {
                class_index: 6,
                name_and_type_index: 15
            },
            classfile.constant_pool[1]);
        assert_eq!(
            Tag::Fieldref {
                class_index: 16,
                name_and_type_index: 17
            },
            classfile.constant_pool[2]);
        assert_eq!(
            Tag::String {
                string_index: 18
            },
            classfile.constant_pool[3]);
        assert_eq!(
            Tag::Methodref {
                class_index: 19,
                name_and_type_index: 20
            },
            classfile.constant_pool[4]);
        assert_eq!(
            Tag::Class {
                name_index: 21
            },
            classfile.constant_pool[5]);
        assert_eq!(
            Tag::Class {
                name_index: 22
            },
            classfile.constant_pool[6]);
        assert_utf8_tag(
            "<init>",
            &classfile.constant_pool[7]);
        assert_utf8_tag(
            "()V",
            &classfile.constant_pool[8]);
        assert_utf8_tag(
            "Code",
            &classfile.constant_pool[9]);
        assert_utf8_tag(
            "LineNumberTable",
            &classfile.constant_pool[10]);
        assert_utf8_tag(
            "main",
            &classfile.constant_pool[11]);
        assert_utf8_tag(
            "([Ljava/lang/String;)V",
            &classfile.constant_pool[12]);
        assert_utf8_tag(
            "SourceFile",
            &classfile.constant_pool[13]);
        assert_utf8_tag(
            "HelloWorld.java",
            &classfile.constant_pool[14]);
        assert_eq!(
            Tag::NameAndType {
                name_index: 7,
                descriptor_index: 8
            },
            classfile.constant_pool[15]);
        assert_eq!(
            Tag::Class {
                name_index: 23
            },
            classfile.constant_pool[16]);
        assert_eq!(
            Tag::NameAndType {
                name_index: 24,
                descriptor_index: 25
            },
            classfile.constant_pool[17]);
        assert_utf8_tag(
            "Hello World!",
            &classfile.constant_pool[18]);
        assert_eq!(
            Tag::Class {
                name_index: 26
            },
            classfile.constant_pool[19]);
        assert_eq!(
            Tag::NameAndType {
                name_index: 27,
                descriptor_index: 28
            },
            classfile.constant_pool[20]);
        assert_utf8_tag(
            "io/hcf/frappe/HelloWorld",
            &classfile.constant_pool[21]);
        assert_utf8_tag(
            "java/lang/Object",
            &classfile.constant_pool[22]);
        assert_utf8_tag(
            "java/lang/System",
            &classfile.constant_pool[23]);
        assert_utf8_tag(
            "out",
            &classfile.constant_pool[24]);
        assert_utf8_tag(
            "Ljava/io/PrintStream;",
            &classfile.constant_pool[25]);
        assert_utf8_tag(
            "java/io/PrintStream",
            &classfile.constant_pool[26]);
        assert_utf8_tag(
            "println",
            &classfile.constant_pool[27]);
        assert_utf8_tag(
            "(Ljava/lang/String;)V",
            &classfile.constant_pool[28]);

        assert_eq!(0, classfile.fields.len());
        assert_eq!(0, classfile.fields.len());

        // 2 methods
        assert_eq!(2, classfile.methods.len());
        // ctor
        let ctor_info = &classfile.methods[0];
        assert_eq!(
            ACC_PUBLIC,
            ctor_info.access_flags);
        assert_utf8_tag(
            "<init>",
            &classfile.constant_pool[ctor_info.name_index]);
        assert_utf8_tag(
            "()V",
            &classfile.constant_pool[ctor_info.descriptor_index]);
        // main
        let main_info = &classfile.methods[1];
        assert_eq!(
            ACC_PUBLIC | ACC_STATIC,
            main_info.access_flags);
        assert_utf8_tag(
            "main",
            &classfile.constant_pool[main_info.name_index]);
        assert_utf8_tag(
            "([Ljava/lang/String;)V",
            &classfile.constant_pool[main_info.descriptor_index]);

        // 1 attribute
        assert_eq!(1, classfile.attributes.len());
    }

    fn assert_utf8_tag(value: &str, tag: &Tag) {
        let expected_tag = Tag::Utf8(value.into());
        assert_eq!(expected_tag, *tag);
    }
}

<|endoftext|>


<commit_before>struct YoungGen {
    young_start: *const u8,
    young_end: *const u8,
    from_start: *const u8,
}<commit_msg>swiper: started with YoungGen<commit_after>use std::ptr;

struct YoungGen {
    total: Region,
    from: Chunk,
    to: Chunk,
}

impl YoungGen {
    fn new(young_start: *const u8, young_end: *const u8) -> YoungGen {
        let half_size = (young_end as usize - young_start as usize) / 2;
        let half_address = unsafe { young_start.offset(half_size as isize) };

        YoungGen {
            total: Region::new(young_start, young_end),
            from: Chunk::new(young_start, half_address),
            to: Chunk::new(half_address,  young_end),
        }
    }
}

struct Region {
    start: *const u8,
    end: *const u8,
}

impl Region {
    fn new(start: *const u8, end: *const u8) -> Region {
        Region {
            start: start,
            end: end,
        }
    }

    fn size(&self) -> usize {
        self.end as usize - self.start as usize
    }
}

struct Chunk {
    start: *const u8,
    uncommitted: *const u8,
    end: *const u8,
}

impl Chunk {
    fn new(start: *const u8, end: *const u8) -> Chunk {
        Chunk {
            start: start,
            uncommitted: start,
            end: end,
        }
    }

    fn empty() -> Chunk {
        Chunk {
            start: ptr::null(),
            uncommitted: ptr::null(),
            end: ptr::null(),
        }
    }

    fn committed_size(&self) -> usize {
        self.uncommitted as usize - self.start as usize
    }

    fn uncommitted_size(&self) -> usize {
        self.end as usize - self.uncommitted as usize
    }
}<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Handle_a_signal
//
// Note that this solution only works on Unix.

extern crate libc;
extern crate time;

use libc::consts::os::posix88::SIGINT;
use libc::funcs::posix01::signal;
use std::io::timer::Timer;
use std::mem;
use std::sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL};
use std::sync::atomics;
use std::time::duration::Duration;

#[cfg(all(unix, not(test)))]
fn main()
{
    // The time between ticks of our counter.
    let duration = Duration::seconds(1) / 2;
    let mut timer = Timer::new().unwrap();
    // "SIGINT received" global variable.
    static mut GOT_SIGINT: AtomicBool = INIT_ATOMIC_BOOL;
    unsafe {
        // Initially, "SIGINT received" is false.
        GOT_SIGINT.store(false, atomics::Release);
        // Interrupt handler that handles the SIGINT signal
        unsafe fn handle_sigint() {
            // It is dangerous to perform any system calls in interrupts, so just set the atomic
            // "SIGINT received" global to true when it arrives.
            GOT_SIGINT.store(true, atomics::Release);
        }
        // Make handle_sigint the signal handler for SIGINT.
        signal::signal(SIGINT, mem::transmute(handle_sigint));
    }
    let periodic = timer.periodic(duration);
    // Get the start time...
    let start = time::precise_time_ns();
    // Integer counter
    let mut i = 0u32;
    // Every `duration`...
    for _ in periodic.iter() {
        // Break if SIGINT was handled
        if unsafe { GOT_SIGINT.load(atomics::Acquire) } { break }
        // Otherwise, increment and display the integer and continue the loop.
        i += 1;
        println!("{}", i);
    }
    // Get the end time.
    let end = time::precise_time_ns();
    // Compute the difference
    let diff = Duration::nanoseconds((end - start) as i64);
    // Print the difference and exit
    println!("Program has run for {} seconds", diff);
}

#[cfg(not(unix))]
fn main()
{
    println!("Not supported on this platform");
}
<commit_msg>Fixing handle_a_signal on Windows.<commit_after>// Implements http://rosettacode.org/wiki/Handle_a_signal
//
// Note that this solution only works on Unix.

extern crate libc;
extern crate time;

use std::io::timer::Timer;
use std::mem;
use std::sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL};
use std::sync::atomics;
use std::time::duration::Duration;

#[cfg(all(unix, not(test)))]
fn main()
{
    use libc::consts::os::posix88::SIGINT;
    use libc::funcs::posix01::signal;

    // The time between ticks of our counter.
    let duration = Duration::seconds(1) / 2;
    let mut timer = Timer::new().unwrap();
    // "SIGINT received" global variable.
    static mut GOT_SIGINT: AtomicBool = INIT_ATOMIC_BOOL;
    unsafe {
        // Initially, "SIGINT received" is false.
        GOT_SIGINT.store(false, atomics::Release);
        // Interrupt handler that handles the SIGINT signal
        unsafe fn handle_sigint() {
            // It is dangerous to perform any system calls in interrupts, so just set the atomic
            // "SIGINT received" global to true when it arrives.
            GOT_SIGINT.store(true, atomics::Release);
        }
        // Make handle_sigint the signal handler for SIGINT.
        signal::signal(SIGINT, mem::transmute(handle_sigint));
    }
    let periodic = timer.periodic(duration);
    // Get the start time...
    let start = time::precise_time_ns();
    // Integer counter
    let mut i = 0u32;
    // Every `duration`...
    for _ in periodic.iter() {
        // Break if SIGINT was handled
        if unsafe { GOT_SIGINT.load(atomics::Acquire) } { break }
        // Otherwise, increment and display the integer and continue the loop.
        i += 1;
        println!("{}", i);
    }
    // Get the end time.
    let end = time::precise_time_ns();
    // Compute the difference
    let diff = Duration::nanoseconds((end - start) as i64);
    // Print the difference and exit
    println!("Program has run for {} seconds", diff);
}

#[cfg(not(unix))]
fn main()
{
    println!("Not supported on this platform");
}
<|endoftext|>


<commit_before>use rustc::lint::Context;
use rustc::middle::const_eval::lookup_const_by_id;
use syntax::ast::*;
use syntax::ptr::P;

pub enum FloatWidth {
    Fw32,
    Fw64,
    FwAny
}

impl From<FloatTy> for FloatWidth {
    fn from(ty: FloatTy) -> FloatWidth {
        match ty {
            TyF32 => Fw32,
            TyF64 => Fw64,
        }
    }
}

/// a Lit_-like enum to fold constant `Expr`s into
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Constant {
    /// a String "abc"
    ConstantStr(&'static str, StrStyle),
    /// a Binary String b"abc"
    ConstantBinary(Rc<Vec<u8>>),
    /// a single byte b'a'
    ConstantByte(u8),
    /// a single char 'a'
    ConstantChar(char),
    /// an integer
    ConstantInt(u64, LitIntType),
    /// a float with given type
    ConstantFloat(Cow<'static, str>, FloatWidth),
    /// true or false
    ConstantBool(bool),
    /// an array of constants
    ConstantVec(Vec<Constant>),
    /// also an array, but with only one constant, repeated N times
    ConstantRepeat(Constant, usize),
    /// a tuple of constants
    ConstantTuple(Vec<Constant>),
}

/// simple constant folding
pub fn constant(cx: &Context, e: &Expr, follow: bool) -> Option<Constant> {
    match e {
        &ExprParen(ref inner) => constant(cx, inner, follow),
        &ExprPath(_, _) => if follow { fetch_path(cx, e) } else { None },
        &ExprBlock(ref block) => constant_block(cx, inner, follow),
        &ExprIf(ref cond, ref then, ref otherwise) =>
            match constant(cx, cond) {
                Some(ConstantBool(true)) => constant(cx, then, follow),
                Some(ConstantBool(false)) => constant(cx, otherwise, follow),
                _ => None,
            },
        &ExprLit(ref lit) => Some(lit_to_constant(lit)),
        &ExprVec(ref vec) => constant_vec(cx, vec, follow),
        &ExprTup(ref tup) => constant_tup(cx, tup, follow),
        &ExprRepeat(ref value, ref number) =>
            constant_binop_apply(cx, value, number,|v, n| ConstantRepeat(v, n)),
        &ExprUnary(op, ref operand) => constant(cx, operand, follow).and_then(
            |o| match op {
                UnNot =>
                    if let ConstantBool(b) = o {
                        Some(ConstantBool(!b))
                    } else { None },
                UnNeg => constant_negate(o),
                UnUniq | UnDeref => o,
            }),
        &ExprBinary(op, ref left, ref right) =>
            constant_binop(cx, op, left, right, follow),
        //TODO: add other expressions
        _ => None,
    }
}

fn lit_to_constant(lit: &Lit_) -> Constant {
    match lit {
        &LitStr(ref is, style) => ConstantStr(&*is, style),
        &LitBinary(ref blob) => ConstantBinary(blob.clone()),
        &LitByte(b) => ConstantByte(b),
        &LitChar(c) => ConstantChar(c),
        &LitInt(value, ty) => ConstantInt(value, ty),
        &LitFloat(ref is, ty) => ConstantFloat(Cow::Borrowed(&*is), ty.into()),
        &LitFloatUnsuffixed(InternedString) =>
                ConstantFloat(Cow::Borrowed(&*is), FwAny),
        &LitBool(b) => ConstantBool(b),
    }
}

/// create `Some(ConstantVec(..))` of all constants, unless there is any
/// non-constant part
fn constant_vec(cx: &Context, vec: &[&Expr], follow: bool) -> Option<Constant> {
    parts = Vec::new();
    for opt_part in vec {
        match constant(cx, opt_part, follow) {
            Some(ref p) => parts.push(p),
            None => { return None; },
        }
    }
    Some(ConstantVec(parts))
}

fn constant_tup(cx: &Context, tup: &[&Expr], follow: bool) -> Option<Constant> {
    parts = Vec::new();
    for opt_part in vec {
        match constant(cx, opt_part, follow) {
            Some(ref p) => parts.push(p),
            None => { return None; },
        }
    }
    Some(ConstantTuple(parts))
}

/// lookup a possibly constant expression from a ExprPath
fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> {
    if let Some(&PathResolution { base_def: DefConst(id), ..}) =
            cx.tcx.def_map.borrow().get(&e.id) {
        lookup_const_by_id(cx.tcx, id, None).map(|l| constant(cx, l))
    } else { None }
}

/// A block can only yield a constant if it only has one constant expression
fn constant_block(cx: &Context, block: &Block, follow: bool) -> Option<Constant> {
    if block.stmts.is_empty() {
        block.expr.map(|b| constant(cx, b, follow))
    } else { None }
}

fn constant_negate(o: Constant) -> Option<Constant> {
    match o {
        &ConstantInt(value, ty) =>
            Some(ConstantInt(value, match ty {
                SignedIntLit(ity, sign) => SignedIntLit(ity, neg_sign(sign)),
                UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)),
                _ => { return None; },
            })),
        &LitFloat(ref is, ref ty) => Some(ConstantFloat(neg_float_str(is), ty)),
        _ => None,
    }
}

fn neg_sign(s: Sign) -> Sign {
    match s {
        Sign::Plus => Sign::Minus,
        Sign::Minus => Sign::Plus,
    }
}

fn neg_float_str(s: &InternedString) -> Cow<'static, str> {
    if s.startsWith('-') {
        Cow::Borrowed(s[1..])
    } else {
        Cow::Owned(format!("-{}", &*s))
    }
}

fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr,
        follow: bool) -> Option<Constant> {
    match op.node {
        //BiAdd,
        //BiSub,
        //BiMul,
        //BiDiv,
        //BiRem,
        BiAnd => constant_short_circuit(cx, left, right, false, follow),
        BiOr => constant_short_circuit(cx, left, right, true, follow),
        //BiBitXor,
        //BiBitAnd,
        //BiBitOr,
        //BiShl,
        //BiShr,
        //BiEq,
        //BiLt,
        //BiLe,
        //BiNe,
        //BiGe,
        //BiGt,
        _ => None,
    }
}

fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F,
        follow: bool) -> Option<Constant>
where F: FnMut(Constant, Constant) -> Option<Constant> {
    constant(cx, left, follow).and_then(|l| constant(cx, right, follow)
        .and_then(|r| op(l, r)))
}

fn constant_short_circuit(cx: &Context, left: &Expr, right: &Expr, b: bool,
        follow: bool) -> Option<Constant> {
    if let ConstantBool(lbool) = constant(cx, left, follow) {
        if l == b {
            Some(ConstantBool(b))
        } else {
            if let ConstantBool(rbool) = constant(cx, right, follow) {
                Some(ConstantBool(rbool))
            } else { None }
        }
    } else { None }
}
<commit_msg>changed Constant to a struct with 'needed_resolution' bool<commit_after>use rustc::lint::Context;
use rustc::middle::const_eval::lookup_const_by_id;
use syntax::ast::*;
use syntax::ptr::P;

pub enum FloatWidth {
    Fw32,
    Fw64,
    FwAny
}

impl From<FloatTy> for FloatWidth {
    fn from(ty: FloatTy) -> FloatWidth {
        match ty {
            TyF32 => Fw32,
            TyF64 => Fw64,
        }
    }
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Constant {
    constant: ConstantVariant,
    needed_resolution: bool
}

impl Constant {
    fn new(variant: ConstantVariant) -> Constant {
        Constant { constant: variant, needed_resolution: false }
    }

    fn new_resolved(variant: ConstantVariant) -> Constant {
        Constant { constant: variant, needed_resolution: true }
    }
}

/// a Lit_-like enum to fold constant `Expr`s into
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum ConstantVariant {
    /// a String "abc"
    ConstantStr(&'static str, StrStyle),
    /// a Binary String b"abc"
    ConstantBinary(Rc<Vec<u8>>),
    /// a single byte b'a'
    ConstantByte(u8),
    /// a single char 'a'
    ConstantChar(char),
    /// an integer
    ConstantInt(u64, LitIntType),
    /// a float with given type
    ConstantFloat(Cow<'static, str>, FloatWidth),
    /// true or false
    ConstantBool(bool),
    /// an array of constants
    ConstantVec(Vec<Constant>),
    /// also an array, but with only one constant, repeated N times
    ConstantRepeat(Constant, usize),
    /// a tuple of constants
    ConstantTuple(Vec<Constant>),
}

impl ConstantVariant {
    /// convert to u64 if possible
    ///
    /// # panics
    ///
    /// if the constant could not be converted to u64 losslessly
    fn as_u64(&self) -> u64 {
        if let &ConstantInt(val, _) = self {
            val // TODO we may want to check the sign if any
        } else {
            panic!("Could not convert a {:?} to u64");
        }
    }
}

/// simple constant folding: Insert an expression, get a constant or none.
pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> {
    match e {
        &ExprParen(ref inner) => constant(cx, inner),
        &ExprPath(_, _) => fetch_path(cx, e),
        &ExprBlock(ref block) => constant_block(cx, inner),
        &ExprIf(ref cond, ref then, ref otherwise) =>
            constant_if(cx, cond, then, otherwise),
        &ExprLit(ref lit) => Some(lit_to_constant(lit)),
        &ExprVec(ref vec) => constant_vec(cx, vec),
        &ExprTup(ref tup) => constant_tup(cx, tup),
        &ExprRepeat(ref value, ref number) =>
            constant_binop_apply(cx, value, number,|v, n| Constant {
                constant: ConstantRepeat(v, n.constant.as_u64()),
                needed_resolution: v.needed_resolution || n.needed_resolution
            }),
        &ExprUnary(op, ref operand) => constant(cx, operand).and_then(
            |o| match op {
                UnNot =>
                    if let ConstantBool(b) = o.variant {
                        Some(Constant{
                            needed_resolution: o.needed_resolution,
                            constant: ConstantBool(!b),
                        })
                    } else { None },
                UnNeg => constant_negate(o),
                UnUniq | UnDeref => o,
            }),
        &ExprBinary(op, ref left, ref right) =>
            constant_binop(op, left, right),
        //TODO: add other expressions
        _ => None,
    }
}

fn lit_to_constant(lit: &Lit_) -> Constant {
    match lit {
        &LitStr(ref is, style) => Constant::new(ConstantStr(&*is, style)),
        &LitBinary(ref blob) => Constant::new(ConstantBinary(blob.clone())),
        &LitByte(b) => Constant::new(ConstantByte(b)),
        &LitChar(c) => Constant::new(ConstantChar(c)),
        &LitInt(value, ty) => Constant::new(ConstantInt(value, ty)),
        &LitFloat(ref is, ty) =>
            Constant::new(ConstantFloat(Cow::Borrowed(&*is), ty.into())),
        &LitFloatUnsuffixed(InternedString) =>
            Constant::new(ConstantFloat(Cow::Borrowed(&*is), FwAny)),
        &LitBool(b) => Constant::new(ConstantBool(b)),
    }
}

/// create `Some(ConstantVec(..))` of all constants, unless there is any
/// non-constant part
fn constant_vec(cx: &Context, vec: &[&Expr]) -> Option<Constant> {
    let mut parts = Vec::new();
    let mut resolved = false;
    for opt_part in vec {
        match constant(cx, opt_part) {
            Some(ref p) => {
                resolved |= p.needed_resolution;
                parts.push(p)
            },
            None => { return None; },
        }
    }
    Some(Constant {
        constant: ConstantVec(parts),
        needed_resolution: resolved
    })
}

fn constant_tup(cx: &Context, tup: &[&Expr]) -> Option<Constant> {
    let mut parts = Vec::new();
    let mut resolved = false;
    for opt_part in vec {
        match constant(cx, opt_part) {
            Some(ref p) => {
                resolved |= p.needed_resolution;
                parts.push(p)
            },
            None => { return None; },
        }
    }
    Some(Constant {
        constant: ConstantTuple(parts),
        needed_resolution: resolved
    })
}

/// lookup a possibly constant expression from a ExprPath
fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> {
    if let Some(&PathResolution { base_def: DefConst(id), ..}) =
            cx.tcx.def_map.borrow().get(&e.id) {
        lookup_const_by_id(cx.tcx, id, None).map(
            |l| Constant::new_resolved(constant(cx, l).constant))
    } else { None }
}

/// A block can only yield a constant if it only has one constant expression
fn constant_block(cx: &Context, block: &Block) -> Option<Constant> {
    if block.stmts.is_empty() {
        block.expr.map(|b| constant(cx, b))
    } else { None }
}

fn constant_if(cx: &Context, cond: &Expr, then: &Expr, otherwise: &Expr) ->
        Option<Constant> {
    if let Some(Constant{ constant: ConstantBool(b), needed_resolution: res }) =
            constant(cx, cond) {
        let part = constant(cx, if b { then } else { otherwise });
        Some(Constant {
            constant: part.constant,
            needed_resolution: res || part.needed_resolution,
        })
    } else { None }
}

fn constant_negate(o: Constant) -> Option<Constant> {
    Some(Constant{
        needed_resolution: o.needed_resolution,
        constant: match o.constant {
            &ConstantInt(value, ty) =>
                ConstantInt(value, match ty {
                    SignedIntLit(ity, sign) =>
                        SignedIntLit(ity, neg_sign(sign)),
                    UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)),
                    _ => { return None; },
                }),
            &LitFloat(ref is, ref ty) => ConstantFloat(neg_float_str(is), ty),
            _ => { return None; },
        }
    })
}

fn neg_sign(s: Sign) -> Sign {
    match s {
        Sign::Plus => Sign::Minus,
        Sign::Minus => Sign::Plus,
    }
}

fn neg_float_str(s: &InternedString) -> Cow<'static, str> {
    if s.startsWith('-') {
        Cow::Borrowed(s[1..])
    } else {
        Cow::Owned(format!("-{}", &*s))
    }
}

fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr)
        -> Option<Constant> {
    match op.node {
        //BiAdd,
        //BiSub,
        //BiMul,
        //BiDiv,
        //BiRem,
        BiAnd => constant_short_circuit(cx, left, right, false),
        BiOr => constant_short_circuit(cx, left, right, true),
        //BiBitXor,
        //BiBitAnd,
        //BiBitOr,
        //BiShl,
        //BiShr,
        //BiEq,
        //BiLt,
        //BiLe,
        //BiNe,
        //BiGe,
        //BiGt,
        _ => None,
    }
}

fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F)
        -> Option<Constant>
where F: FnMut(ConstantVariant, ConstantVariant) -> Option<ConstantVariant> {
    constant(cx, left).and_then(|l| constant(cx, right).and_then(
        |r| Constant {
            needed_resolution: l.needed_resolution || r.needed_resolution,
            constant: op(l.constant, r.constant)
        }))
}

fn constant_short_circuit(cx: &Context, left: &Expr, right: &Expr, b: bool) ->
        Option<Constant> {
    let leftconst = constant(cx, left);
    if let ConstantBool(lbool) = leftconst.constant {
        if l == b {
            Some(leftconst)
        } else {
            let rightconst = constant(cx, right);
            if let ConstantBool(rbool) = rightconst.constant {
                Some(Constant {
                    constant: rightconst.constant,
                    needed_resolution: leftconst.needed_resolution ||
                                       rightconst.needed_resolution,
                })
            } else { None }
        }
    } else { None }
}
<|endoftext|>