<commit_before>use indy::api::ErrorCode;
use indy::api::wallet::*;

use utils::callback::CallbackUtils;
use utils::inmem_wallet::InmemWallet;
use utils::sequence::SequenceUtils;
use utils::environment::EnvironmentUtils;

use std::collections::HashSet;
use std::ffi::CString;
use std::sync::Mutex;
use utils::constants::{TYPE, INMEM_TYPE, WALLET_CREDENTIALS};

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

use serde_json;

pub struct WalletUtils {}

impl WalletUtils {
    pub fn register_wallet_storage(xtype: &str, force_create: bool) -> Result<(), ErrorCode> {
        lazy_static! {
            static ref REGISERED_WALLETS: Mutex<HashSet<String>> = Default::default();
        }

        let mut wallets = REGISERED_WALLETS.lock().unwrap();

        if wallets.contains(xtype) & !force_create {
            // as registering of plugged wallet with
            return Ok(());
        }

        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();

        let xxtype = CString::new(xtype).unwrap();

        let err = indy_register_wallet_storage(
            command_handle,
            xxtype.as_ptr(),
            Some(InmemWallet::create),
            Some(InmemWallet::open),
            Some(InmemWallet::close),
            Some(InmemWallet::delete),
            Some(InmemWallet::add_record),
            Some(InmemWallet::update_record_value),
            Some(InmemWallet::update_record_tags),
            Some(InmemWallet::add_record_tags),
            Some(InmemWallet::delete_record_tags),
            Some(InmemWallet::delete_record),
            Some(InmemWallet::get_record),
            Some(InmemWallet::get_record_id),
            Some(InmemWallet::get_record_type),
            Some(InmemWallet::get_record_value),
            Some(InmemWallet::get_record_tags),
            Some(InmemWallet::free_record),
            Some(InmemWallet::get_storage_metadata),
            Some(InmemWallet::set_storage_metadata),
            Some(InmemWallet::free_storage_metadata),
            Some(InmemWallet::search_records),
            Some(InmemWallet::search_all_records),
            Some(InmemWallet::get_search_total_count),
            Some(InmemWallet::fetch_search_next_record),
            Some(InmemWallet::free_search),
            cb
        );

        wallets.insert(xtype.to_string());

        super::results::result_to_empty(err, receiver)
    }

    pub fn create_wallet(config: &str, credentials: &str) -> Result<(), ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();

        let config = CString::new(config).unwrap();
        let credentials = CString::new(credentials).unwrap();

        let err =
            indy_create_wallet(command_handle,
                               config.as_ptr(),
                               credentials.as_ptr(),
                               cb);

        super::results::result_to_empty(err, receiver)
    }

    pub fn open_wallet(config: &str, credentials: &str) -> Result<i32, ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec_i32();

        let config = CString::new(config).unwrap();
        let credentials = CString::new(credentials).unwrap();

        let err =
            indy_open_wallet(command_handle,
                             config.as_ptr(),
                             credentials.as_ptr(),
                             cb);

        super::results::result_to_int(err, receiver)
    }

    pub fn create_and_open_wallet(storage_type: Option<&str>) -> Result<i32, ErrorCode> {
        let config = json!({
            "id": format!("default-wallet_id-{}", SequenceUtils::get_next_id()),
            "storage_type": storage_type.unwrap_or(TYPE)
        }).to_string();

        WalletUtils::create_wallet(&config, WALLET_CREDENTIALS)?;
        WalletUtils::open_wallet(&config, WALLET_CREDENTIALS)
    }

    pub fn create_and_open_default_wallet() -> Result<i32, ErrorCode> {
        let config = json!({
            "id": format!("default-wallet_id-{}", SequenceUtils::get_next_id()),
            "storage_type": TYPE
        }).to_string();

        WalletUtils::create_wallet(&config, WALLET_CREDENTIALS)?;
        WalletUtils::open_wallet(&config, WALLET_CREDENTIALS)
    }

    pub fn create_and_open_plugged_wallet() -> Result<i32, ErrorCode> {
        let config = json!({
            "id": format!("default-wallet_id-{}", SequenceUtils::get_next_id()),
            "storage_type": INMEM_TYPE
        }).to_string();

        WalletUtils::create_wallet(&config, WALLET_CREDENTIALS)?;
        WalletUtils::open_wallet(&config, WALLET_CREDENTIALS)
    }

    pub fn delete_wallet(config: &str, credentials: &str) -> Result<(), ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();

        let config = CString::new(config).unwrap();
        let credentials = CString::new(credentials).unwrap();

        let err = indy_delete_wallet(command_handle, config.as_ptr(), credentials.as_ptr(), cb);

        super::results::result_to_empty(err, receiver)
    }

    pub fn close_wallet(wallet_handle: i32) -> Result<(), ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();

        let err = indy_close_wallet(command_handle, wallet_handle, cb);

        super::results::result_to_empty(err, receiver)
    }

    pub fn export_wallet(wallet_handle: i32, export_config_json: &str) -> Result<(), ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();
        let export_config_json = CString::new(export_config_json).unwrap();

        let err = indy_export_wallet(command_handle, wallet_handle, export_config_json.as_ptr(), cb);

        super::results::result_to_empty(err, receiver)
    }

    pub fn import_wallet(config: &str, credentials: &str, import_config: &str) -> Result<(), ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();

        let config = CString::new(config).unwrap();
        let credentials = CString::new(credentials).unwrap();
        let import_config = CString::new(import_config).unwrap();

        let err =
            indy_import_wallet(command_handle,
                               config.as_ptr(),
                               credentials.as_ptr(),
                               import_config.as_ptr(),
                               cb);

        super::results::result_to_empty(err, receiver)
    }

    pub fn export_wallet_path() -> PathBuf {
        EnvironmentUtils::tmp_file_path("export_file")
    }

    pub fn prepare_export_wallet_config(path: &Path) -> String {
        let json = json!({
            "path": path.to_str().unwrap(),
            "key": "export_key",
        });
        serde_json::to_string(&json).unwrap()
    }
}<commit_msg>- Integration tests fixed<commit_after>use indy::api::ErrorCode;
use indy::api::wallet::*;

use utils::callback::CallbackUtils;
use utils::inmem_wallet::InmemWallet;
use utils::sequence::SequenceUtils;
use utils::environment::EnvironmentUtils;

use std::collections::HashSet;
use std::ffi::CString;
use std::sync::Mutex;
use utils::constants::{TYPE, INMEM_TYPE, WALLET_CREDENTIALS};

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

use serde_json;

pub struct WalletUtils {}

impl WalletUtils {
    pub fn register_wallet_storage(xtype: &str, force_create: bool) -> Result<(), ErrorCode> {
        lazy_static! {
            static ref REGISERED_WALLETS: Mutex<HashSet<String>> = Default::default();
        }

        let mut wallets = REGISERED_WALLETS.lock().unwrap();

        if wallets.contains(xtype) & !force_create {
            // as registering of plugged wallet with
            return Ok(());
        }

        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();

        let xxtype = CString::new(xtype).unwrap();

        let err = indy_register_wallet_storage(
            command_handle,
            xxtype.as_ptr(),
            Some(InmemWallet::create),
            Some(InmemWallet::open),
            Some(InmemWallet::close),
            Some(InmemWallet::delete),
            Some(InmemWallet::add_record),
            Some(InmemWallet::update_record_value),
            Some(InmemWallet::update_record_tags),
            Some(InmemWallet::add_record_tags),
            Some(InmemWallet::delete_record_tags),
            Some(InmemWallet::delete_record),
            Some(InmemWallet::get_record),
            Some(InmemWallet::get_record_id),
            Some(InmemWallet::get_record_type),
            Some(InmemWallet::get_record_value),
            Some(InmemWallet::get_record_tags),
            Some(InmemWallet::free_record),
            Some(InmemWallet::get_storage_metadata),
            Some(InmemWallet::set_storage_metadata),
            Some(InmemWallet::free_storage_metadata),
            Some(InmemWallet::search_records),
            Some(InmemWallet::search_all_records),
            Some(InmemWallet::get_search_total_count),
            Some(InmemWallet::fetch_search_next_record),
            Some(InmemWallet::free_search),
            cb
        );

        wallets.insert(xtype.to_string());

        super::results::result_to_empty(err, receiver)
    }

    pub fn create_wallet(config: &str, credentials: &str) -> Result<(), ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();

        let config = CString::new(config).unwrap();
        let credentials = CString::new(credentials).unwrap();

        let err =
            indy_create_wallet(command_handle,
                               config.as_ptr(),
                               credentials.as_ptr(),
                               cb);

        super::results::result_to_empty(err, receiver)
    }

    pub fn open_wallet(config: &str, credentials: &str) -> Result<i32, ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec_i32();

        let config = CString::new(config).unwrap();
        let credentials = CString::new(credentials).unwrap();

        let err =
            indy_open_wallet(command_handle,
                             config.as_ptr(),
                             credentials.as_ptr(),
                             cb);

        super::results::result_to_int(err, receiver)
    }

    pub fn create_and_open_wallet(storage_type: Option<&str>) -> Result<i32, ErrorCode> {
        let config = json!({
            "id": format!("default-wallet_id-{}", SequenceUtils::get_next_id()),
            "storage_type": storage_type.unwrap_or(TYPE)
        }).to_string();

        WalletUtils::create_wallet(&config, WALLET_CREDENTIALS)?;
        WalletUtils::open_wallet(&config, WALLET_CREDENTIALS)
    }

    pub fn create_and_open_default_wallet() -> Result<i32, ErrorCode> {
        let config = json!({
            "id": format!("default-wallet_id-{}", SequenceUtils::get_next_id()),
            "storage_type": TYPE
        }).to_string();

        WalletUtils::create_wallet(&config, WALLET_CREDENTIALS)?;
        WalletUtils::open_wallet(&config, WALLET_CREDENTIALS)
    }

    pub fn create_and_open_plugged_wallet() -> Result<i32, ErrorCode> {
        let config = json!({
            "id": format!("default-wallet_id-{}", SequenceUtils::get_next_id()),
            "storage_type": INMEM_TYPE
        }).to_string();

        WalletUtils::register_wallet_storage("inmem", false).unwrap();
        WalletUtils::create_wallet(&config, WALLET_CREDENTIALS)?;
        WalletUtils::open_wallet(&config, WALLET_CREDENTIALS)
    }

    pub fn delete_wallet(config: &str, credentials: &str) -> Result<(), ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();

        let config = CString::new(config).unwrap();
        let credentials = CString::new(credentials).unwrap();

        let err = indy_delete_wallet(command_handle, config.as_ptr(), credentials.as_ptr(), cb);

        super::results::result_to_empty(err, receiver)
    }

    pub fn close_wallet(wallet_handle: i32) -> Result<(), ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();

        let err = indy_close_wallet(command_handle, wallet_handle, cb);

        super::results::result_to_empty(err, receiver)
    }

    pub fn export_wallet(wallet_handle: i32, export_config_json: &str) -> Result<(), ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();
        let export_config_json = CString::new(export_config_json).unwrap();

        let err = indy_export_wallet(command_handle, wallet_handle, export_config_json.as_ptr(), cb);

        super::results::result_to_empty(err, receiver)
    }

    pub fn import_wallet(config: &str, credentials: &str, import_config: &str) -> Result<(), ErrorCode> {
        let (receiver, command_handle, cb) = CallbackUtils::_closure_to_cb_ec();

        let config = CString::new(config).unwrap();
        let credentials = CString::new(credentials).unwrap();
        let import_config = CString::new(import_config).unwrap();

        let err =
            indy_import_wallet(command_handle,
                               config.as_ptr(),
                               credentials.as_ptr(),
                               import_config.as_ptr(),
                               cb);

        super::results::result_to_empty(err, receiver)
    }

    pub fn export_wallet_path() -> PathBuf {
        EnvironmentUtils::tmp_file_path("export_file")
    }

    pub fn prepare_export_wallet_config(path: &Path) -> String {
        let json = json!({
            "path": path.to_str().unwrap(),
            "key": "export_key",
        });
        serde_json::to_string(&json).unwrap()
    }
}<|endoftext|>


<commit_before>//! If you use enough force, you can actually use this GC to implement a toy VM.

use builtins;
use cell_gc::{GcHeapSession, GcLeaf};
use cell_gc::collections::VecRef;
use compile::{self, Expr};
use parse;
use value::{InternedString, Pair, Value};
use value::Value::*;

/// A potentially partially evaluated value.
pub enum Trampoline<'h> {
    /// A completely evaluated value.
    Value(Value<'h>),
    /// The continuation of a partial evaluation in tail position. The stack
    /// should be unwound before resumption of its evaluation.
    TailCall {
        func: Value<'h>,
        args: Vec<Value<'h>>,
    },
}

impl<'h> Trampoline<'h> {
    /// Complete the evaluation of this value. Avoids recursion to implement
    /// proper tail calls and keep from blowing the stack.
    pub fn eval(mut self, hs: &mut GcHeapSession<'h>) -> Result<Value<'h>, String> {
        while let Trampoline::TailCall { func, args } = self {
            self = apply(hs, func, args)?;
        }
        match self {
            Trampoline::Value(v) => Ok(v),
            Trampoline::TailCall { .. } => unreachable!(),
        }
    }
}

#[derive(Clone, Debug, PartialEq, IntoHeap)]
pub struct Environment<'h> {
    parent: Option<EnvironmentRef<'h>>,
    names: VecRef<'h, GcLeaf<InternedString>>,
    values: VecRef<'h, Value<'h>>,
}

impl<'h> Environment<'h> {
    pub fn default_env(hs: &mut GcHeapSession<'h>) -> EnvironmentRef<'h> {
        let env = Environment {
            parent: None,
            names: hs.alloc(vec![]),
            values: hs.alloc(vec![]),
        };
        let env = hs.alloc(env);

        builtins::define_builtins(hs, env.clone());

        const PRELUDE: &'static str = include_str!("prelude.sch");
        let prelude = match parse::parse(hs, PRELUDE) {
            Ok(forms) => forms,
            Err(err) => panic!("unexpected error parsing prelude: {}", err),
        };

        for expr in prelude {
            if let Err(err) = eval(hs, expr, env.clone()) {
                panic!("unexpected error evaluating prelude: {}", err);
            }
        }
        env
    }
}

impl<'h> EnvironmentRef<'h> {
    pub fn push(&self, key: InternedString, value: Value<'h>) {
        self.names().push(GcLeaf::new(key));
        self.values().push(value);
    }

    pub fn lookup(&self, name: InternedString) -> Result<(EnvironmentRef<'h>, usize), String> {
        let mut next = Some(self.clone());
        while let Some(env) = next {
            let names = env.names();
            for i in (0..names.len()).rev() {
                if name == *names.get(i) {
                    return Ok((env, i));
                }
            }
            next = env.parent();
        }
        Err(format!("undefined symbol: {:?}", name.as_str()))
    }

    pub fn get(&self, name: InternedString) -> Result<Value<'h>, String> {
        let (env, i) = self.lookup(name)?;
        Ok(env.values().get(i))
    }

    pub fn set(&self, name: InternedString, value: Value<'h>) -> Result<(), String> {
        let (env, i) = self.lookup(name)?;
        env.values().set(i, value);
        Ok(())
    }
}

#[macro_export]
macro_rules! lisp {
    { ( ) , $_hs:expr } => {
        Nil
    };
    { ( $h:tt $($t:tt)* ) , $hs:expr } => {
        {
            let h = lisp!($h, $hs);
            let t = lisp!(($($t)*), $hs);
            Cons($hs.alloc(Pair { car: h, cdr: t }))
        }
    };
    { $s:tt , $_hs:expr } => {
        {
            let s = stringify!($s);  // lame, but nothing else matches after an `ident` match fails
            if s.starts_with(|c: char| c.is_digit(10)) {
                Int(s.parse().expect("invalid numeric literal in `lisp!`"))
            } else {
                Symbol($crate::cell_gc::GcLeaf::new($crate::value::InternedString::get(s)))
            }
        }
    };
}

pub fn apply<'h>(
    hs: &mut GcHeapSession<'h>,
    fval: Value<'h>,
    mut args: Vec<Value<'h>>,
) -> Result<Trampoline<'h>, String> {
    match fval {
        Builtin(f) => (f.0)(hs, args),
        Lambda(pair) => {
            let code = match pair.car() {
                Code(code) => code,
                _ => panic!("internal error: bad lambda"),
            };
            let parent = Some(match pair.cdr() {
                Environment(pe) => pe,
                _ => panic!("internal error: bad lambda"),
            });
            let names = code.params();
            let n_names = names.len();
            let has_rest = code.rest();

            let n_required_params = n_names - has_rest as usize;
            if args.len() < n_required_params {
                return Err("apply: not enough arguments".to_string());
            }
            if has_rest {
                let mut rest_list = Nil;
                for v in args.drain(n_required_params..).rev() {
                    rest_list = Cons(hs.alloc(Pair {
                        car: v,
                        cdr: rest_list,
                    }));
                }
                args.push(rest_list);
            } else if args.len() > n_required_params {
                return Err("apply: too many arguments".to_string());
            }

            assert_eq!(names.len(), args.len());
            let values = hs.alloc(args);
            let env = hs.alloc(Environment {
                parent,
                names,
                values,
            });

            eval_to_tail_call(hs, code.body(), env)
        }
        _ => Err("apply: not a function".to_string()),
    }
}

/// Evaluate `expr` until we reach a tail call, at which point it is packaged up
/// as a `Trampoline::TailCall` and returned so we can unwind the stack before
/// continuing evaluation.
pub fn eval_to_tail_call<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Expr<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Trampoline<'h>, String> {
    match expr {
        Expr::Con(k) =>
            Ok(Trampoline::Value(k)),
        Expr::Var(s) =>
            Ok(Trampoline::Value(env.get(s.unwrap())?)),
        Expr::Fun(code) =>
            Ok(Trampoline::Value(Lambda(hs.alloc(Pair {
                car: Value::Code(code),
                cdr: Value::Environment(env.clone()),
            })))),
        Expr::App(subexprs) => {
            let func = eval_compiled(hs, subexprs.get(0), env.clone())?;
            let args: Vec<Value<'h>> =
                (1..subexprs.len())
                .map(|i| eval_compiled(hs, subexprs.get(i), env.clone()))
                .collect::<Result<Vec<Value<'h>>, String>>()?;
            Ok(Trampoline::TailCall { func, args })
        }
        Expr::Seq(exprs) => {
            let len = exprs.len();
            if len == 0 {
                Ok(Trampoline::Value(Nil))
            } else {
                for i in 0..(len - 1) {
                    eval_compiled(hs, exprs.get(i), env.clone())?;
                }
                eval_to_tail_call(hs, exprs.get(len - 1), env)
            }
        }
        Expr::If(if_parts) => {
            let cond_value = eval_compiled(hs, if_parts.cond(), env.clone())?;
            let selected_expr =
                if cond_value.to_bool() {
                    if_parts.t_expr()
                } else {
                    if_parts.f_expr()
                };
            eval_to_tail_call(hs, selected_expr, env)
        }
        Expr::Letrec(letrec) => {
            let names = letrec.names();
            let values: VecRef<'h, Value<'h>> =
                hs.alloc((0..names.len()).map(|_| Value::Nil).collect::<Vec<Value<'h>>>());
            let letrec_env =
                hs.alloc(Environment {
                    parent: Some(env),
                    names,
                    values: values.clone(),
                });
            let exprs = letrec.exprs();
            for i in 0..exprs.len() {
                let val = eval_compiled(hs, exprs.get(i), letrec_env.clone())?;
                values.set(i, val);
            }
            eval_to_tail_call(hs, letrec.body(), letrec_env)
        }
        Expr::Def(def) => {
            let val = eval_compiled(hs, def.value(), env.clone())?;
            env.push(def.name().unwrap(), val);
            Ok(Trampoline::Value(Value::Unspecified))
        }
        Expr::Set(def) => {
            let val = eval_compiled(hs, def.value(), env.clone())?;
            env.set(def.name().unwrap(), val)?;
            Ok(Trampoline::Value(Value::Unspecified))
        }
        Expr::ToplevelEnv => {
            let mut env = env;
            while let Some(parent) = env.parent() {
                env = parent;
            }
            Ok(Trampoline::Value(Value::Environment(env)))
        }
    }
}

pub fn eval_compiled<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Expr<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Value<'h>, String> {
    let tail = eval_to_tail_call(hs, expr, env)?;
    tail.eval(hs)
}

pub fn eval<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Value<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Value<'h>, String> {
    let expr = compile::compile_toplevel(hs, expr)?;
    eval_compiled(hs, expr, env)
}

#[cfg(test)]
include!("tests.rs");
<commit_msg>lisp: Light refactoring of Trampoline::eval.<commit_after>//! If you use enough force, you can actually use this GC to implement a toy VM.

use builtins;
use cell_gc::{GcHeapSession, GcLeaf};
use cell_gc::collections::VecRef;
use compile::{self, Expr};
use parse;
use value::{InternedString, Pair, Value};
use value::Value::*;

/// A potentially partially evaluated value.
pub enum Trampoline<'h> {
    /// A completely evaluated value.
    Value(Value<'h>),
    /// The continuation of a partial evaluation in tail position. The stack
    /// should be unwound before resumption of its evaluation.
    TailCall {
        func: Value<'h>,
        args: Vec<Value<'h>>,
    },
}

impl<'h> Trampoline<'h> {
    /// Complete the evaluation of this value. Avoids recursion to implement
    /// proper tail calls and keep from blowing the stack.
    pub fn eval(mut self, hs: &mut GcHeapSession<'h>) -> Result<Value<'h>, String> {
        loop {
            match self {
                Trampoline::Value(v) => {
                    return Ok(v);
                }
                Trampoline::TailCall { func, args } => {
                    self = apply(hs, func, args)?;
                }
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq, IntoHeap)]
pub struct Environment<'h> {
    parent: Option<EnvironmentRef<'h>>,
    names: VecRef<'h, GcLeaf<InternedString>>,
    values: VecRef<'h, Value<'h>>,
}

impl<'h> Environment<'h> {
    pub fn default_env(hs: &mut GcHeapSession<'h>) -> EnvironmentRef<'h> {
        let env = Environment {
            parent: None,
            names: hs.alloc(vec![]),
            values: hs.alloc(vec![]),
        };
        let env = hs.alloc(env);

        builtins::define_builtins(hs, env.clone());

        const PRELUDE: &'static str = include_str!("prelude.sch");
        let prelude = match parse::parse(hs, PRELUDE) {
            Ok(forms) => forms,
            Err(err) => panic!("unexpected error parsing prelude: {}", err),
        };

        for expr in prelude {
            if let Err(err) = eval(hs, expr, env.clone()) {
                panic!("unexpected error evaluating prelude: {}", err);
            }
        }
        env
    }
}

impl<'h> EnvironmentRef<'h> {
    pub fn push(&self, key: InternedString, value: Value<'h>) {
        self.names().push(GcLeaf::new(key));
        self.values().push(value);
    }

    pub fn lookup(&self, name: InternedString) -> Result<(EnvironmentRef<'h>, usize), String> {
        let mut next = Some(self.clone());
        while let Some(env) = next {
            let names = env.names();
            for i in (0..names.len()).rev() {
                if name == *names.get(i) {
                    return Ok((env, i));
                }
            }
            next = env.parent();
        }
        Err(format!("undefined symbol: {:?}", name.as_str()))
    }

    pub fn get(&self, name: InternedString) -> Result<Value<'h>, String> {
        let (env, i) = self.lookup(name)?;
        Ok(env.values().get(i))
    }

    pub fn set(&self, name: InternedString, value: Value<'h>) -> Result<(), String> {
        let (env, i) = self.lookup(name)?;
        env.values().set(i, value);
        Ok(())
    }
}

#[macro_export]
macro_rules! lisp {
    { ( ) , $_hs:expr } => {
        Nil
    };
    { ( $h:tt $($t:tt)* ) , $hs:expr } => {
        {
            let h = lisp!($h, $hs);
            let t = lisp!(($($t)*), $hs);
            Cons($hs.alloc(Pair { car: h, cdr: t }))
        }
    };
    { $s:tt , $_hs:expr } => {
        {
            let s = stringify!($s);  // lame, but nothing else matches after an `ident` match fails
            if s.starts_with(|c: char| c.is_digit(10)) {
                Int(s.parse().expect("invalid numeric literal in `lisp!`"))
            } else {
                Symbol($crate::cell_gc::GcLeaf::new($crate::value::InternedString::get(s)))
            }
        }
    };
}

pub fn apply<'h>(
    hs: &mut GcHeapSession<'h>,
    fval: Value<'h>,
    mut args: Vec<Value<'h>>,
) -> Result<Trampoline<'h>, String> {
    match fval {
        Builtin(f) => (f.0)(hs, args),
        Lambda(pair) => {
            let code = match pair.car() {
                Code(code) => code,
                _ => panic!("internal error: bad lambda"),
            };
            let parent = Some(match pair.cdr() {
                Environment(pe) => pe,
                _ => panic!("internal error: bad lambda"),
            });
            let names = code.params();
            let n_names = names.len();
            let has_rest = code.rest();

            let n_required_params = n_names - has_rest as usize;
            if args.len() < n_required_params {
                return Err("apply: not enough arguments".to_string());
            }
            if has_rest {
                let mut rest_list = Nil;
                for v in args.drain(n_required_params..).rev() {
                    rest_list = Cons(hs.alloc(Pair {
                        car: v,
                        cdr: rest_list,
                    }));
                }
                args.push(rest_list);
            } else if args.len() > n_required_params {
                return Err("apply: too many arguments".to_string());
            }

            assert_eq!(names.len(), args.len());
            let values = hs.alloc(args);
            let env = hs.alloc(Environment {
                parent,
                names,
                values,
            });

            eval_to_tail_call(hs, code.body(), env)
        }
        _ => Err("apply: not a function".to_string()),
    }
}

/// Evaluate `expr` until we reach a tail call, at which point it is packaged up
/// as a `Trampoline::TailCall` and returned so we can unwind the stack before
/// continuing evaluation.
pub fn eval_to_tail_call<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Expr<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Trampoline<'h>, String> {
    match expr {
        Expr::Con(k) =>
            Ok(Trampoline::Value(k)),
        Expr::Var(s) =>
            Ok(Trampoline::Value(env.get(s.unwrap())?)),
        Expr::Fun(code) =>
            Ok(Trampoline::Value(Lambda(hs.alloc(Pair {
                car: Value::Code(code),
                cdr: Value::Environment(env.clone()),
            })))),
        Expr::App(subexprs) => {
            let func = eval_compiled(hs, subexprs.get(0), env.clone())?;
            let args: Vec<Value<'h>> =
                (1..subexprs.len())
                .map(|i| eval_compiled(hs, subexprs.get(i), env.clone()))
                .collect::<Result<Vec<Value<'h>>, String>>()?;
            Ok(Trampoline::TailCall { func, args })
        }
        Expr::Seq(exprs) => {
            let len = exprs.len();
            if len == 0 {
                Ok(Trampoline::Value(Nil))
            } else {
                for i in 0..(len - 1) {
                    eval_compiled(hs, exprs.get(i), env.clone())?;
                }
                eval_to_tail_call(hs, exprs.get(len - 1), env)
            }
        }
        Expr::If(if_parts) => {
            let cond_value = eval_compiled(hs, if_parts.cond(), env.clone())?;
            let selected_expr =
                if cond_value.to_bool() {
                    if_parts.t_expr()
                } else {
                    if_parts.f_expr()
                };
            eval_to_tail_call(hs, selected_expr, env)
        }
        Expr::Letrec(letrec) => {
            let names = letrec.names();
            let values: VecRef<'h, Value<'h>> =
                hs.alloc((0..names.len()).map(|_| Value::Nil).collect::<Vec<Value<'h>>>());
            let letrec_env =
                hs.alloc(Environment {
                    parent: Some(env),
                    names,
                    values: values.clone(),
                });
            let exprs = letrec.exprs();
            for i in 0..exprs.len() {
                let val = eval_compiled(hs, exprs.get(i), letrec_env.clone())?;
                values.set(i, val);
            }
            eval_to_tail_call(hs, letrec.body(), letrec_env)
        }
        Expr::Def(def) => {
            let val = eval_compiled(hs, def.value(), env.clone())?;
            env.push(def.name().unwrap(), val);
            Ok(Trampoline::Value(Value::Unspecified))
        }
        Expr::Set(def) => {
            let val = eval_compiled(hs, def.value(), env.clone())?;
            env.set(def.name().unwrap(), val)?;
            Ok(Trampoline::Value(Value::Unspecified))
        }
        Expr::ToplevelEnv => {
            let mut env = env;
            while let Some(parent) = env.parent() {
                env = parent;
            }
            Ok(Trampoline::Value(Value::Environment(env)))
        }
    }
}

pub fn eval_compiled<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Expr<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Value<'h>, String> {
    let tail = eval_to_tail_call(hs, expr, env)?;
    tail.eval(hs)
}

pub fn eval<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Value<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Value<'h>, String> {
    let expr = compile::compile_toplevel(hs, expr)?;
    eval_compiled(hs, expr, env)
}

#[cfg(test)]
include!("tests.rs");
<|endoftext|>


<commit_before>use time;
use std::io::timer::sleep;
use gl;
use gl::types::GLint;

use {
    Gl,
    GameWindow,
};
use keyboard;
use mouse;
use event;

/// Render argument.
pub struct RenderArgs<'a> {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// OpenGL back-end for Rust-Graphics.
    pub gl: &'a mut Gl,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
pub struct MouseMoveArgs {
    /// y.
    pub x: f64,
    /// x.
    pub y: f64,
}

/// Mouse relative move arguments.
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Contains the different game events.
pub enum GameEvent<'a> {
    /// Render graphics.
    Render(RenderArgs<'a>),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs)
}

impl<'a> GameEvent<'a> {
    /// Maps event to something that can be sent between tasks if possible.
    ///
    /// Render events are not sendable between tasks.
    pub fn to_sendable(&'a self) -> Option<GameEvent<'static>> {
        match *self {
            Render(_) => None,
            Update(args) => Some(Update(args)),
            KeyPress(args) => Some(KeyPress(args)),
            KeyRelease(args) => Some(KeyRelease(args)),
            MousePress(args) => Some(MousePress(args)),
            MouseRelease(args) => Some(MouseRelease(args)),
            MouseMove(args) => Some(MouseMove(args)),
            MouseRelativeMove(args) => Some(MouseRelativeMove(args)),
        }
    }
}

enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    PrepareUpdateLoopState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// Settings for the game loop behavior.
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
/// loop {
///     match game_iter.next() {
///         None => { break },
///         Some(e) => match e {
///             Render(args) => {
///                 // Do rendering here.
///             },
///             _ => {},
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    game_window: &'a mut W,
    state: GameIteratorState,
    gl: Gl,
    bg_color: [f32, ..4],
    last_update: u64,
    update_time_in_ns: u64,
    dt: f64,
    min_updates_per_frame: u64,
    min_ns_per_frame: u64,
    start_render: u64,
    next_render: u64,
    updated: u64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(game_window: &'a mut W, settings: &GameIteratorSettings) -> GameIterator<'a, W> {
        let bg_color = game_window.get_settings().background_color;
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            gl: Gl::new(),
            last_update: start,
            update_time_in_ns: billion / updates_per_second,
            dt: 1.0 / updates_per_second as f64,
            // You can make this lower if needed.
            min_updates_per_frame: updates_per_second / max_frames_per_second,
            min_ns_per_frame: billion / max_frames_per_second,
            start_render: start,
            next_render: start,
            bg_color: bg_color,
            updated: 0,
        }
    }

    /// Returns the next game event.
    pub fn next<'a>(&'a mut self) -> Option<GameEvent<'a>> {
        match self.state {
            RenderState => {
                if self.game_window.should_close() { return None; }

                self.start_render = time::precise_time_ns();
                // Rendering code
                let (w, h) = self.game_window.get_size();
                if w != 0 && h != 0 {
                    gl::Viewport(0, 0, w as GLint, h as GLint);
                    let r = self.bg_color[0];
                    let g = self.bg_color[1];
                    let b = self.bg_color[2];
                    let a = self.bg_color[3];
                    gl::ClearColor(r, g, b, a);
                    gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
                    // Swap buffers next time.
                    self.state = SwapBuffersState;
                    return Some(Render(RenderArgs {
                            // Extrapolate time forward to allow smooth motion.
                            // 'start_render' is always bigger than 'last_update'.
                            ext_dt: (self.start_render - self.last_update) as f64 / billion as f64,
                            gl: &mut self.gl,
                            width: w,
                            height: h,
                        }
                    ));
                }

                self.state = PrepareUpdateLoopState;
                return self.next();
            },
            SwapBuffersState => {
                self.game_window.swap_buffers();
                self.state = PrepareUpdateLoopState;
                return self.next();
            },
            PrepareUpdateLoopState => {
                self.updated = 0;
                self.next_render = self.start_render + self.min_ns_per_frame;
                self.state = UpdateLoopState;
                return self.next();
            },
            UpdateLoopState => {
                let got_min_updates = self.updated < self.min_updates_per_frame;
                let got_time_to_update = time::precise_time_ns() < self.next_render;
                let before_next_frame = self.last_update + self.update_time_in_ns < self.next_render;

                if ( got_time_to_update || got_min_updates ) && before_next_frame {
                    self.state = HandleEventsState;
                    return self.next();
                }

                // Wait if possible.
                // Convert to ms because that is what the sleep function takes.
                let t = (self.next_render - time::precise_time_ns() ) / 1_000_000;
                if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                          // which tells us that t should have been negative
                                          // and we are running slow and shouldn't sleep.
                    sleep( t );
                }
                self.state = RenderState;
                return self.next();
            },
            HandleEventsState => {
                // Handle all events before updating.
                return match self.game_window.poll_event() {
                    event::KeyPressed(key) => {
                        Some(KeyPress(KeyPressArgs {
                            key: key,
                        }))
                    },
                    event::KeyReleased(key) => {
                        Some(KeyRelease(KeyReleaseArgs {
                            key: key,
                        }))
                    },
                    event::MouseButtonPressed(mouse_button) => {
                        Some(MousePress(MousePressArgs {
                            button: mouse_button,
                        }))
                    },
                    event::MouseButtonReleased(mouse_button) => {
                        Some(MouseRelease(MouseReleaseArgs {
                            button: mouse_button,
                        }))
                    },
                    event::MouseMoved(x, y, relative_move) => {
                        match relative_move {
                            Some((dx, dy)) =>
                                self.state = MouseRelativeMoveState(dx, dy),
                            None => {},
                        };
                        Some(MouseMove(MouseMoveArgs {
                            x: x,
                            y: y,
                        }))
                    },
                    event::NoEvent => {
                        self.state = UpdateState;
                        self.next()
                    },
                }
            },
            MouseRelativeMoveState(dx, dy) => {
                self.state = HandleEventsState;
                return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                    dx: dx,
                    dy: dy,
                }));
            },
            UpdateState => {
                self.updated += 1;
                self.state = UpdateLoopState;
                self.last_update += self.update_time_in_ns;
                return Some(Update(UpdateArgs{
                    dt: self.dt,
                }));
            },
        };

        /*
        // copied.

        while !self.should_close(game_window) {

            let start_render = time::precise_time_ns();

            // Rendering code
            let (w, h) = game_window.get_size();
            if w != 0 && h != 0 {
                self.viewport(game_window);
                let mut gl = Gl::new(&mut gl_data, asset_store);
                bg.clear(&mut gl);
                // Extrapolate time forward to allow smooth motion.
                // 'now' is always bigger than 'last_update'.
                let ext_dt = (start_render - last_update) as f64 / billion as f64;
                self.render(
                    ext_dt,
                    &context
                        .trans(-1.0, 1.0)
                        .scale(2.0 / w as f64, -2.0 / h as f64)
                        .store_view(),
                    &mut gl
                        );
                self.swap_buffers(game_window);
            }

            let next_render = start_render + min_ns_per_frame;

            // Update gamestate
            let mut updated = 0;

            while // If we haven't reached the required number of updates yet
                  ( updated < min_updates_per_frame ||
                    // Or we have the time to update further
                    time::precise_time_ns() < next_render ) &&
                  //And we haven't already progressed time to far
                  last_update + update_time_in_ns < next_render {

                self.handle_events(game_window, asset_store);
                self.update(dt, asset_store);

                updated += 1;
                last_update += update_time_in_ns;
            }

            // Wait if possible

            let t = (next_render - time::precise_time_ns() ) / 1_000_000;
            if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                      // which tells us that t should have been negative
                                      // and we are running slow and shouldn't sleep.
                sleep( t );
            }

        }
        */
    }
}

<commit_msg>Added creation of graphics context to `GameIterator` docs<commit_after>use time;
use std::io::timer::sleep;
use gl;
use gl::types::GLint;

use {
    Gl,
    GameWindow,
};
use keyboard;
use mouse;
use event;

/// Render argument.
pub struct RenderArgs<'a> {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// OpenGL back-end for Rust-Graphics.
    pub gl: &'a mut Gl,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
pub struct MouseMoveArgs {
    /// y.
    pub x: f64,
    /// x.
    pub y: f64,
}

/// Mouse relative move arguments.
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Contains the different game events.
pub enum GameEvent<'a> {
    /// Render graphics.
    Render(RenderArgs<'a>),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs)
}

impl<'a> GameEvent<'a> {
    /// Maps event to something that can be sent between tasks if possible.
    ///
    /// Render events are not sendable between tasks.
    pub fn to_sendable(&'a self) -> Option<GameEvent<'static>> {
        match *self {
            Render(_) => None,
            Update(args) => Some(Update(args)),
            KeyPress(args) => Some(KeyPress(args)),
            KeyRelease(args) => Some(KeyRelease(args)),
            MousePress(args) => Some(MousePress(args)),
            MouseRelease(args) => Some(MouseRelease(args)),
            MouseMove(args) => Some(MouseMove(args)),
            MouseRelativeMove(args) => Some(MouseRelativeMove(args)),
        }
    }
}

enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    PrepareUpdateLoopState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// Settings for the game loop behavior.
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
/// loop {
///     match game_iter.next() {
///         None => { break },
///         Some(e) => match e {
///             Render(args) => {
///                 // Create graphics context with absolute coordinates.
///                 let c = Context::abs(args.width as f64, args.height as f64);
///                 // Do rendering here.
///             },
///             _ => {},
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    game_window: &'a mut W,
    state: GameIteratorState,
    gl: Gl,
    bg_color: [f32, ..4],
    last_update: u64,
    update_time_in_ns: u64,
    dt: f64,
    min_updates_per_frame: u64,
    min_ns_per_frame: u64,
    start_render: u64,
    next_render: u64,
    updated: u64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(game_window: &'a mut W, settings: &GameIteratorSettings) -> GameIterator<'a, W> {
        let bg_color = game_window.get_settings().background_color;
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            gl: Gl::new(),
            last_update: start,
            update_time_in_ns: billion / updates_per_second,
            dt: 1.0 / updates_per_second as f64,
            // You can make this lower if needed.
            min_updates_per_frame: updates_per_second / max_frames_per_second,
            min_ns_per_frame: billion / max_frames_per_second,
            start_render: start,
            next_render: start,
            bg_color: bg_color,
            updated: 0,
        }
    }

    /// Returns the next game event.
    pub fn next<'a>(&'a mut self) -> Option<GameEvent<'a>> {
        match self.state {
            RenderState => {
                if self.game_window.should_close() { return None; }

                self.start_render = time::precise_time_ns();
                // Rendering code
                let (w, h) = self.game_window.get_size();
                if w != 0 && h != 0 {
                    gl::Viewport(0, 0, w as GLint, h as GLint);
                    let r = self.bg_color[0];
                    let g = self.bg_color[1];
                    let b = self.bg_color[2];
                    let a = self.bg_color[3];
                    gl::ClearColor(r, g, b, a);
                    gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
                    // Swap buffers next time.
                    self.state = SwapBuffersState;
                    return Some(Render(RenderArgs {
                            // Extrapolate time forward to allow smooth motion.
                            // 'start_render' is always bigger than 'last_update'.
                            ext_dt: (self.start_render - self.last_update) as f64 / billion as f64,
                            gl: &mut self.gl,
                            width: w,
                            height: h,
                        }
                    ));
                }

                self.state = PrepareUpdateLoopState;
                return self.next();
            },
            SwapBuffersState => {
                self.game_window.swap_buffers();
                self.state = PrepareUpdateLoopState;
                return self.next();
            },
            PrepareUpdateLoopState => {
                self.updated = 0;
                self.next_render = self.start_render + self.min_ns_per_frame;
                self.state = UpdateLoopState;
                return self.next();
            },
            UpdateLoopState => {
                let got_min_updates = self.updated < self.min_updates_per_frame;
                let got_time_to_update = time::precise_time_ns() < self.next_render;
                let before_next_frame = self.last_update + self.update_time_in_ns < self.next_render;

                if ( got_time_to_update || got_min_updates ) && before_next_frame {
                    self.state = HandleEventsState;
                    return self.next();
                }

                // Wait if possible.
                // Convert to ms because that is what the sleep function takes.
                let t = (self.next_render - time::precise_time_ns() ) / 1_000_000;
                if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                          // which tells us that t should have been negative
                                          // and we are running slow and shouldn't sleep.
                    sleep( t );
                }
                self.state = RenderState;
                return self.next();
            },
            HandleEventsState => {
                // Handle all events before updating.
                return match self.game_window.poll_event() {
                    event::KeyPressed(key) => {
                        Some(KeyPress(KeyPressArgs {
                            key: key,
                        }))
                    },
                    event::KeyReleased(key) => {
                        Some(KeyRelease(KeyReleaseArgs {
                            key: key,
                        }))
                    },
                    event::MouseButtonPressed(mouse_button) => {
                        Some(MousePress(MousePressArgs {
                            button: mouse_button,
                        }))
                    },
                    event::MouseButtonReleased(mouse_button) => {
                        Some(MouseRelease(MouseReleaseArgs {
                            button: mouse_button,
                        }))
                    },
                    event::MouseMoved(x, y, relative_move) => {
                        match relative_move {
                            Some((dx, dy)) =>
                                self.state = MouseRelativeMoveState(dx, dy),
                            None => {},
                        };
                        Some(MouseMove(MouseMoveArgs {
                            x: x,
                            y: y,
                        }))
                    },
                    event::NoEvent => {
                        self.state = UpdateState;
                        self.next()
                    },
                }
            },
            MouseRelativeMoveState(dx, dy) => {
                self.state = HandleEventsState;
                return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                    dx: dx,
                    dy: dy,
                }));
            },
            UpdateState => {
                self.updated += 1;
                self.state = UpdateLoopState;
                self.last_update += self.update_time_in_ns;
                return Some(Update(UpdateArgs{
                    dt: self.dt,
                }));
            },
        };

        /*
        // copied.

        while !self.should_close(game_window) {

            let start_render = time::precise_time_ns();

            // Rendering code
            let (w, h) = game_window.get_size();
            if w != 0 && h != 0 {
                self.viewport(game_window);
                let mut gl = Gl::new(&mut gl_data, asset_store);
                bg.clear(&mut gl);
                // Extrapolate time forward to allow smooth motion.
                // 'now' is always bigger than 'last_update'.
                let ext_dt = (start_render - last_update) as f64 / billion as f64;
                self.render(
                    ext_dt,
                    &context
                        .trans(-1.0, 1.0)
                        .scale(2.0 / w as f64, -2.0 / h as f64)
                        .store_view(),
                    &mut gl
                        );
                self.swap_buffers(game_window);
            }

            let next_render = start_render + min_ns_per_frame;

            // Update gamestate
            let mut updated = 0;

            while // If we haven't reached the required number of updates yet
                  ( updated < min_updates_per_frame ||
                    // Or we have the time to update further
                    time::precise_time_ns() < next_render ) &&
                  //And we haven't already progressed time to far
                  last_update + update_time_in_ns < next_render {

                self.handle_events(game_window, asset_store);
                self.update(dt, asset_store);

                updated += 1;
                last_update += update_time_in_ns;
            }

            // Wait if possible

            let t = (next_render - time::precise_time_ns() ) / 1_000_000;
            if t > 1 && t < 1000000 { // The second half just checks if it overflowed,
                                      // which tells us that t should have been negative
                                      // and we are running slow and shouldn't sleep.
                sleep( t );
            }

        }
        */
    }
}

<|endoftext|>


<commit_before>#![crate_name = "uu_hostid"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Maciej Dziardziel <fiedzia@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate libc;

#[macro_use]
extern crate uucore;

use libc::c_long;

static SYNTAX: &str = "[options]";
static SUMMARY: &str = "";
static LONG_HELP: &str = "";

pub enum Mode {
    HostId,
    Help,
    Version,
}

// currently rust libc interface doesn't include gethostid
extern "C" {
    pub fn gethostid() -> c_long;
}

pub fn uumain(args: Vec<String>) -> i32 {
    new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);
    hostid();
    0
}

fn hostid() {
    /*
     * POSIX says gethostid returns a "32-bit identifier" but is silent
     * whether it's sign-extended.  Turn off any sign-extension.  This
     * is a no-op unless unsigned int is wider than 32 bits.
     */

    let mut result: c_long;
    unsafe {
        result = gethostid();
    }

    result &= 0xffff_ffff;
    println!("{:0>8x}", result);
}
<commit_msg>hostid: remove old enum<commit_after>#![crate_name = "uu_hostid"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Maciej Dziardziel <fiedzia@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate libc;

#[macro_use]
extern crate uucore;

use libc::c_long;

static SYNTAX: &str = "[options]";
static SUMMARY: &str = "";
static LONG_HELP: &str = "";

// currently rust libc interface doesn't include gethostid
extern "C" {
    pub fn gethostid() -> c_long;
}

pub fn uumain(args: Vec<String>) -> i32 {
    new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);
    hostid();
    0
}

fn hostid() {
    /*
     * POSIX says gethostid returns a "32-bit identifier" but is silent
     * whether it's sign-extended.  Turn off any sign-extension.  This
     * is a no-op unless unsigned int is wider than 32 bits.
     */

    let mut result: c_long;
    unsafe {
        result = gethostid();
    }

    result &= 0xffff_ffff;
    println!("{:0>8x}", result);
}
<|endoftext|>


<commit_before>use noise::{Seed, Brownian2, Brownian3, perlin2, perlin3};

use field::Field;

pub struct HeightMap {
  pub height: Brownian2<f64, fn (&Seed, &[f64; 2]) -> f64>,
  pub features: Brownian3<f64, fn (&Seed, &[f64; 3]) -> f64>,
  pub seed: Seed,
}

impl HeightMap {
  pub fn new(seed: Seed) -> HeightMap {
    let perlin2: fn(&Seed, &[f64; 2]) -> f64 = perlin2;
    let perlin3: fn(&Seed, &[f64; 3]) -> f64 = perlin3;
    HeightMap {
      seed: seed,
      height:
        Brownian2::new(perlin2, 5)
        .frequency(1.0 / 8.0)
        .persistence(4.0)
        .lacunarity(1.0 / 3.0)
      ,
      features:
        Brownian3::new(perlin3, 2)
        .frequency(1.0 / 64.0)
        .persistence(1.0 / 16.0)
        .lacunarity(8.0)
      ,
    }
  }
}

impl Field for HeightMap {
  /// The height of the field at a given x,y,z.
  fn density_at(&self, x: f32, y: f32, z: f32) -> f32 {
    let coords = [x as f64, z as f64];
    let height = 32.0 + self.height.apply(&self.seed, &coords);
    let height = height as f32;
    height - y
  }
}
<commit_msg>Remove height offset<commit_after>use noise::{Seed, Brownian2, Brownian3, perlin2, perlin3};

use field::Field;

pub struct HeightMap {
  pub height: Brownian2<f64, fn (&Seed, &[f64; 2]) -> f64>,
  pub features: Brownian3<f64, fn (&Seed, &[f64; 3]) -> f64>,
  pub seed: Seed,
}

impl HeightMap {
  pub fn new(seed: Seed) -> HeightMap {
    let perlin2: fn(&Seed, &[f64; 2]) -> f64 = perlin2;
    let perlin3: fn(&Seed, &[f64; 3]) -> f64 = perlin3;
    HeightMap {
      seed: seed,
      height:
        Brownian2::new(perlin2, 5)
        .frequency(1.0 / 8.0)
        .persistence(4.0)
        .lacunarity(1.0 / 3.0)
      ,
      features:
        Brownian3::new(perlin3, 2)
        .frequency(1.0 / 64.0)
        .persistence(1.0 / 16.0)
        .lacunarity(8.0)
      ,
    }
  }
}

impl Field for HeightMap {
  /// The height of the field at a given x,y,z.
  fn density_at(&self, x: f32, y: f32, z: f32) -> f32 {
    let coords = [x as f64, z as f64];
    let height = self.height.apply(&self.seed, &coords);
    let height = height as f32;
    height - y
  }
}
<|endoftext|>


<commit_before>//! This module contains the compiler. The compiler parses source code and generates byte code
//! suitable for execution by the VM.
//!
//! The complation process can be divided into the following phases:
//!
//! 1. Parsing
//! 2. Checking
//! 3. Resolving
//! 4. Linting / Optimizing
//! 5. Emitting
//!
//! This module provides several helper methods that will either wrap up the whole compilation
//! process or stop after a step, to enable more advanced uses of the compiler.
//!
//! Below is a brief description of what each phase does.
//!
//! ## Parsing
//!
//! This phase runs the generated Lea parser. It is generated at compile-time from the Parsing
//! Expression Grammar (PEG) in `lea.rustpeg` with help of the `rust-peg` crate.
//!
//! ## Checking
//!
//! In `check.rs`, a `Checker` visitor is implemented, which runs over an AST and verifies that all
//! statements and expressions are used in a valid context. Since the PEG parser has no state, it
//! cannot do this (and it is better - though slower - to do it this way, since it separates
//! syntax error and context-dependant errors).
//!
//! For example, the checker will deny a `break` statement used outside of a loop and the varargs
//! expression `...` outside of a varargs function.
//!
//! ## Resolving
//!
//! The resolver implemented in `resolve.rs` transforms any named variable (`VNamed` in the AST) to
//! a local, upvalue, or global reference. This makes it easy to see which identifier refers to
//! which variable (might be useful for code highlighting in IDEs) and makes the emitter a bit
//! simpler, since it doesn't have to figure out what an identifier means if it encounters it: It
//! already knows, since the resolver stored it in the AST.
//!
//! ## Linting / Optimizing
//!
//! In this step, all configured Lints and Optimizers are run on the resolved AST. Internally, we
//! make no distinction between a Lint and an Optimizer: Both take a `Function` node, do
//! something to it, and return a transformed `Function` along with a list of warnings to be
//! issued.
//!
//! Most Lints will just return the unmodified function and generate some warnings, while most
//! optimizers will modify the AST, but return no warnings. Of course, there might be exceptions.
//!
//! Lints and Optimizers are implemented in the files inside the "transform" directory:
//!
//! * `fold.rs` implements a constant folding optimization that looks for operators that are
//!   applied to literals, applies them at compile-time, and replaces the node with the result.
//!   This is a basic optimization performed by most compilers (Lua does this too).
//!
//! * `globalwrite.rs` implements a Lint that will warn for all assignments to globals. Global
//!   variables are generally meant to hold the standard library functions, and not much more. User
//!   code should always prefer locals, and modules are meant to return the module when loaded,
//!   which should be assigned to a local by the code that `require`d the module. If you still need
//!   to access a global (for example, when setting up a sandbox), you can do so explicitly by
//!   indexing `_ENV`.
//!
//! * `deprecated_ops.rs` is a Lint that emits a warning whenever a Lua operator is used that has
//!   an equivalent replacement in Lea.
//!
//! ## Emitting
//!
//! The byte code emitter takes a resolved AST and emits byte code for each function that can be
//! executed by the VM.

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate log;

extern crate rustc_serialize;
extern crate term;

extern crate lea_core;
extern crate lea_parser as parser;

use transform::{Transform, LintMode};
use emitter::emit_func;

use ast::Function;

mod errors;
mod check;
mod ast;
mod emitter;
mod resolve;
pub mod transform;

pub use errors::*;
pub use lea_core::fndata::FnData;

/// Defines options that can be used to tweak the compilation process (optimizations, lints, ...)
pub struct CompileConfig<'a> {
    /// AST transforms to apply. All transforms are applied in the order specified here.
    trans: Vec<(&'a Transform, LintMode)>,
}

impl<'a> CompileConfig<'a> {
    /// Creates an empty `CompileConfig` that runs no lints
    pub fn empty() -> CompileConfig<'a> {
        CompileConfig {
            trans: vec![],
        }
    }

    /// Creates a `CompileConfig` that will apply named lints. Returns `None` if a Lint doesn't
    /// exist (TODO).
    pub fn named_lints(names: &[&str]) -> Option<CompileConfig<'a>> {
        let mut conf = CompileConfig::empty();
        for name in names {
            match transform::TRANSFORMS.get(name) {
                None => { return None; },
                Some(tr) => {
                    conf.trans.push((tr, LintMode::Warn));
                }
            }
        }

        Some(conf)
    }

    pub fn add_transform(&mut self, tr: &'a Transform, mode: LintMode) {
        self.trans.push((tr, mode));
    }
}

impl<'a> Default for CompileConfig<'a> {
    /// Creates a default `CompileConfig` that applies the default set of optimizers and lints
    fn default() -> CompileConfig<'a> {
        CompileConfig {
            trans: transform::TRANSFORMS_DEFAULT.iter()
                .map(|&(name, lvl)| (transform::TRANSFORMS.get(name).unwrap(), lvl)).collect(),
        }
    }
}

/// Output of a successful compilation.
pub struct CompileOutput<'a> {
    /// Warnings generated by Lints
    pub warns: Vec<Warning>,
    /// AST node of main function
    pub main: Function<'a>,
    /// Prototype of main function, to be instantiated and run by the VM
    pub mainproto: FnData,
}

/// Parses and checks the given source code (stops after compilation step 2). Returns a valid
/// `Function` node on success.
///
/// If this succeeds, this means that the program described by the source code is valid and can be
/// compiled.
pub fn parse_and_check(code: &str) -> CompileResult<Function> {
    match parser::parse_main(code) {
        Err(e) => Err(ErrParse(e)),
        Ok(main) => {
            let main = main.into();
            let res = check::check_func(&main);
            match res {
                Err(errs) => Err(ErrCheck(errs)),
                Ok(()) => {
                    Ok(main)
                }
            }
        }
    }
}

/// Parses, checks and resolves the given source code (stops after compilation step 3). Returns the
/// resolved main function on success.
pub fn parse_and_resolve(code: &str) -> CompileResult<Function> {
    let mut main = try!(parse_and_check(code));
    main = resolve::resolve_func(main);

    Ok(main)
}

/// Applies all transforms in the given `CompileConfig` to a `main` function. Returns all warnings
/// generated by the transforms. `main` must be resolved beforehand.
///
/// If any transform is configured to cause a compilation error, a corresponding error will be
/// returned.
pub fn apply_transforms<'a>(mut main: Function<'a>, conf: &CompileConfig) -> (Function<'a>, CompileResult<Vec<Warning>>) {
    let mut warnings: Vec<Warning> = Vec::new();
    let mut errwarns: Vec<Warning> = Vec::new();  // warnings handled as errors
    for &(tr, mode) in &conf.trans {
        let (newmain, new_warns) = tr(main);
        main = newmain;

        if mode == LintMode::Error && !new_warns.is_empty() {
            errwarns.extend(new_warns);
        } else {
            warnings.extend(new_warns);
        }
    }

    (main, if errwarns.is_empty() {
        Ok(warnings)
    } else {
        Err(ErrLint(errwarns))
    })
}

/// Compiles source code into an `FnData` instance. This executes the whole compilation process and
/// emits byte code.
///
/// Note that this will not return the `Function` node on error, even if parsing succeeded.
///
/// # Parameters
///
/// * `code` - The source code to compile
/// * `source_name` - The name of this source code. Used when reporting errors. This should be
///   a file name or something similar.
/// * `conf` - The `CompileConfig` to use for this compilation
pub fn compile_str<'a>(code: &'a str, source_name: &str, conf: &CompileConfig) -> CompileResult<CompileOutput<'a>> {
    let main = try!(parse_and_resolve(code));
    let (main, tr_res) = apply_transforms(main, &conf);
    let warnings = try!(tr_res);
    let emit_res = emit_func(&main, source_name);

    match emit_res {
        Ok(proto) => Ok(CompileOutput {
            warns: warnings,
            main: main,
            mainproto: proto,
        }),
        Err(errs) => Err(ErrEmit(errs)),
    }
}

/// Compiles an expression into an `FnData` object that will return the result(s) of the expression
/// to the caller.
pub fn compile_expr<'a>(expr: &'a str, source_name: &str, conf: &CompileConfig) -> CompileResult<CompileOutput<'a>> {
    let main = try!(parser::parse_expr_as_main(expr));
    let main = main.into();
    try!(check::check_func(&main));
    let main = resolve::resolve_func(main);
    let (main, tr_res) = apply_transforms(main, &conf);
    let warnings = try!(tr_res);
    let emit_res = emit_func(&main, source_name);

    match emit_res {
        Ok(proto) => Ok(CompileOutput {
            warns: warnings,
            main: main,
            mainproto: proto,
        }),
        Err(errs) => Err(ErrEmit(errs)),
    }
}
<commit_msg>Fix for regression<commit_after>//! This module contains the compiler. The compiler parses source code and generates byte code
//! suitable for execution by the VM.
//!
//! The complation process can be divided into the following phases:
//!
//! 1. Parsing
//! 2. Checking
//! 3. Resolving
//! 4. Linting / Optimizing
//! 5. Emitting
//!
//! This module provides several helper methods that will either wrap up the whole compilation
//! process or stop after a step, to enable more advanced uses of the compiler.
//!
//! Below is a brief description of what each phase does.
//!
//! ## Parsing
//!
//! This phase runs the generated Lea parser. It is generated at compile-time from the Parsing
//! Expression Grammar (PEG) in `lea.rustpeg` with help of the `rust-peg` crate.
//!
//! ## Checking
//!
//! In `check.rs`, a `Checker` visitor is implemented, which runs over an AST and verifies that all
//! statements and expressions are used in a valid context. Since the PEG parser has no state, it
//! cannot do this (and it is better - though slower - to do it this way, since it separates
//! syntax error and context-dependant errors).
//!
//! For example, the checker will deny a `break` statement used outside of a loop and the varargs
//! expression `...` outside of a varargs function.
//!
//! ## Resolving
//!
//! The resolver implemented in `resolve.rs` transforms any named variable (`VNamed` in the AST) to
//! a local, upvalue, or global reference. This makes it easy to see which identifier refers to
//! which variable (might be useful for code highlighting in IDEs) and makes the emitter a bit
//! simpler, since it doesn't have to figure out what an identifier means if it encounters it: It
//! already knows, since the resolver stored it in the AST.
//!
//! ## Linting / Optimizing
//!
//! In this step, all configured Lints and Optimizers are run on the resolved AST. Internally, we
//! make no distinction between a Lint and an Optimizer: Both take a `Function` node, do
//! something to it, and return a transformed `Function` along with a list of warnings to be
//! issued.
//!
//! Most Lints will just return the unmodified function and generate some warnings, while most
//! optimizers will modify the AST, but return no warnings. Of course, there might be exceptions.
//!
//! Lints and Optimizers are implemented in the files inside the "transform" directory:
//!
//! * `fold.rs` implements a constant folding optimization that looks for operators that are
//!   applied to literals, applies them at compile-time, and replaces the node with the result.
//!   This is a basic optimization performed by most compilers (Lua does this too).
//!
//! * `globalwrite.rs` implements a Lint that will warn for all assignments to globals. Global
//!   variables are generally meant to hold the standard library functions, and not much more. User
//!   code should always prefer locals, and modules are meant to return the module when loaded,
//!   which should be assigned to a local by the code that `require`d the module. If you still need
//!   to access a global (for example, when setting up a sandbox), you can do so explicitly by
//!   indexing `_ENV`.
//!
//! * `deprecated_ops.rs` is a Lint that emits a warning whenever a Lua operator is used that has
//!   an equivalent replacement in Lea.
//!
//! ## Emitting
//!
//! The byte code emitter takes a resolved AST and emits byte code for each function that can be
//! executed by the VM.

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate log;

extern crate rustc_serialize;
extern crate term;

extern crate lea_core;
extern crate lea_parser as parser;

use transform::{Transform, LintMode};
use emitter::emit_func;

use ast::Function;

mod errors;
mod check;
mod ast;
mod emitter;
mod resolve;
pub mod transform;

pub use errors::*;
pub use lea_core::fndata::FnData;

/// Defines options that can be used to tweak the compilation process (optimizations, lints, ...)
pub struct CompileConfig<'a> {
    /// AST transforms to apply. All transforms are applied in the order specified here.
    trans: Vec<(&'a Transform, LintMode)>,
}

impl<'a> CompileConfig<'a> {
    /// Creates an empty `CompileConfig` that runs no lints
    pub fn empty() -> CompileConfig<'a> {
        CompileConfig {
            trans: vec![],
        }
    }

    /// Creates a `CompileConfig` that will apply named lints. Returns `None` if a Lint doesn't
    /// exist (TODO).
    pub fn named_lints(names: &[&str]) -> Option<CompileConfig<'a>> {
        let mut conf = CompileConfig::empty();
        for name in names {
            match transform::TRANSFORMS.get(*name) {
                None => { return None; },
                Some(tr) => {
                    conf.trans.push((tr, LintMode::Warn));
                }
            }
        }

        Some(conf)
    }

    pub fn add_transform(&mut self, tr: &'a Transform, mode: LintMode) {
        self.trans.push((tr, mode));
    }
}

impl<'a> Default for CompileConfig<'a> {
    /// Creates a default `CompileConfig` that applies the default set of optimizers and lints
    fn default() -> CompileConfig<'a> {
        CompileConfig {
            trans: transform::TRANSFORMS_DEFAULT.iter()
                .map(|&(name, lvl)| (transform::TRANSFORMS.get(name).unwrap(), lvl)).collect(),
        }
    }
}

/// Output of a successful compilation.
pub struct CompileOutput<'a> {
    /// Warnings generated by Lints
    pub warns: Vec<Warning>,
    /// AST node of main function
    pub main: Function<'a>,
    /// Prototype of main function, to be instantiated and run by the VM
    pub mainproto: FnData,
}

/// Parses and checks the given source code (stops after compilation step 2). Returns a valid
/// `Function` node on success.
///
/// If this succeeds, this means that the program described by the source code is valid and can be
/// compiled.
pub fn parse_and_check(code: &str) -> CompileResult<Function> {
    match parser::parse_main(code) {
        Err(e) => Err(ErrParse(e)),
        Ok(main) => {
            let main = main.into();
            let res = check::check_func(&main);
            match res {
                Err(errs) => Err(ErrCheck(errs)),
                Ok(()) => {
                    Ok(main)
                }
            }
        }
    }
}

/// Parses, checks and resolves the given source code (stops after compilation step 3). Returns the
/// resolved main function on success.
pub fn parse_and_resolve(code: &str) -> CompileResult<Function> {
    let mut main = try!(parse_and_check(code));
    main = resolve::resolve_func(main);

    Ok(main)
}

/// Applies all transforms in the given `CompileConfig` to a `main` function. Returns all warnings
/// generated by the transforms. `main` must be resolved beforehand.
///
/// If any transform is configured to cause a compilation error, a corresponding error will be
/// returned.
pub fn apply_transforms<'a>(mut main: Function<'a>, conf: &CompileConfig) -> (Function<'a>, CompileResult<Vec<Warning>>) {
    let mut warnings: Vec<Warning> = Vec::new();
    let mut errwarns: Vec<Warning> = Vec::new();  // warnings handled as errors
    for &(tr, mode) in &conf.trans {
        let (newmain, new_warns) = tr(main);
        main = newmain;

        if mode == LintMode::Error && !new_warns.is_empty() {
            errwarns.extend(new_warns);
        } else {
            warnings.extend(new_warns);
        }
    }

    (main, if errwarns.is_empty() {
        Ok(warnings)
    } else {
        Err(ErrLint(errwarns))
    })
}

/// Compiles source code into an `FnData` instance. This executes the whole compilation process and
/// emits byte code.
///
/// Note that this will not return the `Function` node on error, even if parsing succeeded.
///
/// # Parameters
///
/// * `code` - The source code to compile
/// * `source_name` - The name of this source code. Used when reporting errors. This should be
///   a file name or something similar.
/// * `conf` - The `CompileConfig` to use for this compilation
pub fn compile_str<'a>(code: &'a str, source_name: &str, conf: &CompileConfig) -> CompileResult<CompileOutput<'a>> {
    let main = try!(parse_and_resolve(code));
    let (main, tr_res) = apply_transforms(main, &conf);
    let warnings = try!(tr_res);
    let emit_res = emit_func(&main, source_name);

    match emit_res {
        Ok(proto) => Ok(CompileOutput {
            warns: warnings,
            main: main,
            mainproto: proto,
        }),
        Err(errs) => Err(ErrEmit(errs)),
    }
}

/// Compiles an expression into an `FnData` object that will return the result(s) of the expression
/// to the caller.
pub fn compile_expr<'a>(expr: &'a str, source_name: &str, conf: &CompileConfig) -> CompileResult<CompileOutput<'a>> {
    let main = try!(parser::parse_expr_as_main(expr));
    let main = main.into();
    try!(check::check_func(&main));
    let main = resolve::resolve_func(main);
    let (main, tr_res) = apply_transforms(main, &conf);
    let warnings = try!(tr_res);
    let emit_res = emit_func(&main, source_name);

    match emit_res {
        Ok(proto) => Ok(CompileOutput {
            warns: warnings,
            main: main,
            mainproto: proto,
        }),
        Err(errs) => Err(ErrEmit(errs)),
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::sync::{Once, ONCE_INIT};
use std::{mem, raw};
use std::collections::HashMap;
use libc::{self, c_int, c_long, c_double, size_t};
use super::{consts, err, info, opt};
use super::err::ErrCode;
use http::body::Body;
use http::{header, Response};

use curl_ffi as ffi;

pub type ProgressCb<'a> = FnMut(usize, usize, usize, usize) + 'a;

pub struct Easy {
    curl: *mut ffi::CURL
}

impl Easy {
    pub fn new() -> Easy {
        // Ensure that curl is globally initialized
        global_init();

        let handle = unsafe {
            let p = ffi::curl_easy_init();
            ffi::curl_easy_setopt(p, opt::NOPROGRESS, 0);
            p
        };

        Easy { curl: handle }
    }

    #[inline]
    pub fn setopt<T: opt::OptVal>(&mut self, option: opt::Opt, val: T) -> Result<(), err::ErrCode> {
        // TODO: Prevent setting callback related options
        let mut res = err::ErrCode(err::OK);

        unsafe {
            val.with_c_repr(|repr| {
                res = err::ErrCode(ffi::curl_easy_setopt(self.curl, option, repr));
            })
        }

        if res.is_success() { Ok(()) } else { Err(res) }
    }

    pub fn perform(&mut self,
                   body: Option<&mut Body>,
                   progress: Option<Box<ProgressCb>>)
                   -> Result<Response, err::ErrCode> {
        let mut builder = ResponseBuilder::new();

        unsafe {
            let resp_p: usize = mem::transmute(&builder);
            let body_p: usize = match body {
                Some(b) => mem::transmute(b),
                None => 0
            };

            let progress_p: usize = match progress.as_ref() {
                Some(cb) => mem::transmute(cb),
                None => 0
            };

            // Set callback options
            ffi::curl_easy_setopt(self.curl, opt::READFUNCTION, curl_read_fn);
            ffi::curl_easy_setopt(self.curl, opt::READDATA, body_p);

            ffi::curl_easy_setopt(self.curl, opt::WRITEFUNCTION, curl_write_fn);
            ffi::curl_easy_setopt(self.curl, opt::WRITEDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::HEADERFUNCTION, curl_header_fn);
            ffi::curl_easy_setopt(self.curl, opt::HEADERDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::PROGRESSFUNCTION, curl_progress_fn);
            ffi::curl_easy_setopt(self.curl, opt::PROGRESSDATA, progress_p);
        }

        let err = err::ErrCode(unsafe { ffi::curl_easy_perform(self.curl) });

        // If the request failed, abort here
        if !err.is_success() {
            return Err(err);
        }

        // Try to get the response code
        builder.code = try!(self.get_response_code());

        Ok(builder.build())
    }

    pub fn get_response_code(&self) -> Result<u32, err::ErrCode> {
        Ok(try!(self.get_info_long(info::RESPONSE_CODE)) as u32)
    }

    pub fn get_total_time(&self) -> Result<usize, err::ErrCode> {
        Ok(try!(self.get_info_long(info::TOTAL_TIME)) as usize)
    }

    fn get_info_long(&self, key: info::Key) -> Result<c_long, err::ErrCode> {
        let v: c_long = 0;
        let res = err::ErrCode(unsafe {
            ffi::curl_easy_getinfo(self.curl as *const _, key, &v)
        });

        if !res.is_success() {
            return Err(res);
        }

        Ok(v)
    }
}

#[inline]
fn global_init() {
    // Schedule curl to be cleaned up after we're done with this whole process
    static INIT: Once = ONCE_INIT;
    INIT.call_once(|| unsafe {
        assert_eq!(libc::atexit(cleanup), 0);
    });

    extern fn cleanup() {
        unsafe { ffi::curl_global_cleanup() }
    }
}

impl Drop for Easy {
    fn drop(&mut self) {
        unsafe { ffi::curl_easy_cleanup(self.curl) }
    }
}

/*
 *
 * TODO: Move this into handle
 *
 */

struct ResponseBuilder {
    code: u32,
    hdrs: HashMap<String,Vec<String>>,
    body: Vec<u8>
}

impl ResponseBuilder {
    fn new() -> ResponseBuilder {
        ResponseBuilder {
            code: 0,
            hdrs: HashMap::new(),
            body: Vec::new()
        }
    }

    fn add_header(&mut self, name: &str, val: &str) {
        // TODO: Reduce allocations
        use std::ascii::OwnedAsciiExt;
        let name = name.to_string().into_ascii_lowercase();

        let inserted = match self.hdrs.get_mut(&name) {
            Some(vals) => {
                vals.push(val.to_string());
                true
            }
            None => false
        };

        if !inserted {
            self.hdrs.insert(name, vec!(val.to_string()));
        }
    }

    fn build(self) -> Response {
        let ResponseBuilder { code, hdrs, body } = self;
        Response::new(code, hdrs, body)
    }
}

/*
 *
 * ===== Callbacks =====
 */

pub extern "C" fn curl_read_fn(p: *mut u8, size: size_t, nmemb: size_t, body: *mut Body) -> size_t {
    if body.is_null() {
        return 0;
    }

    let dst : &mut [u8] = unsafe { mem::transmute(raw::Slice { data: p, len: (size * nmemb) as usize } )};
    let body: &mut Body = unsafe { mem::transmute(body) };

    match body.read(dst.as_mut_slice()) {
        Ok(len) => len as size_t,
        Err(_) => consts::CURL_READFUNC_ABORT as size_t,
    }
}

pub extern "C" fn curl_write_fn(p: *mut u8, size: size_t, nmemb: size_t, resp: *mut ResponseBuilder) -> size_t {
    if !resp.is_null() {
        let builder: &mut ResponseBuilder = unsafe { mem::transmute(resp) };
        let chunk : &[u8] = unsafe { mem::transmute(raw::Slice { data: p, len: (size * nmemb) as usize } )};
        builder.body.push_all(chunk.as_slice());
    }

    size * nmemb
}

pub extern "C" fn curl_header_fn(p: *mut u8, size: size_t, nmemb: size_t, resp: &mut ResponseBuilder) -> size_t {
    // TODO: Skip the first call (it seems to be the status line)

    let vec : &[u8] = unsafe { mem::transmute(raw::Slice { data: p, len: (size * nmemb) as usize } )};

    match header::parse(vec.as_slice()) {
        Some((name, val)) => {
            resp.add_header(name, val);
        }
        None => {}
    }

    vec.len() as size_t
}

pub extern "C" fn curl_progress_fn(cb: *mut Box<ProgressCb>, dltotal: c_double, dlnow: c_double, ultotal: c_double, ulnow: c_double) -> c_int {
    #[inline]
    fn to_usize(v: c_double) -> usize {
        if v > 0.0 { v as usize } else { 0 }
    }

    if !cb.is_null() {
        let cb: &mut ProgressCb = unsafe { &mut **cb };
        (*cb)(to_usize(dltotal), to_usize(dlnow), to_usize(ultotal), to_usize(ulnow));
    }

    0
}
<commit_msg>Use AsciiExt instead of OwnedAsciiExt<commit_after>#![allow(dead_code)]

use std::sync::{Once, ONCE_INIT};
use std::{mem, raw};
use std::collections::HashMap;
use libc::{self, c_int, c_long, c_double, size_t};
use super::{consts, err, info, opt};
use super::err::ErrCode;
use http::body::Body;
use http::{header, Response};

use curl_ffi as ffi;

pub type ProgressCb<'a> = FnMut(usize, usize, usize, usize) + 'a;

pub struct Easy {
    curl: *mut ffi::CURL
}

impl Easy {
    pub fn new() -> Easy {
        // Ensure that curl is globally initialized
        global_init();

        let handle = unsafe {
            let p = ffi::curl_easy_init();
            ffi::curl_easy_setopt(p, opt::NOPROGRESS, 0);
            p
        };

        Easy { curl: handle }
    }

    #[inline]
    pub fn setopt<T: opt::OptVal>(&mut self, option: opt::Opt, val: T) -> Result<(), err::ErrCode> {
        // TODO: Prevent setting callback related options
        let mut res = err::ErrCode(err::OK);

        unsafe {
            val.with_c_repr(|repr| {
                res = err::ErrCode(ffi::curl_easy_setopt(self.curl, option, repr));
            })
        }

        if res.is_success() { Ok(()) } else { Err(res) }
    }

    pub fn perform(&mut self,
                   body: Option<&mut Body>,
                   progress: Option<Box<ProgressCb>>)
                   -> Result<Response, err::ErrCode> {
        let mut builder = ResponseBuilder::new();

        unsafe {
            let resp_p: usize = mem::transmute(&builder);
            let body_p: usize = match body {
                Some(b) => mem::transmute(b),
                None => 0
            };

            let progress_p: usize = match progress.as_ref() {
                Some(cb) => mem::transmute(cb),
                None => 0
            };

            // Set callback options
            ffi::curl_easy_setopt(self.curl, opt::READFUNCTION, curl_read_fn);
            ffi::curl_easy_setopt(self.curl, opt::READDATA, body_p);

            ffi::curl_easy_setopt(self.curl, opt::WRITEFUNCTION, curl_write_fn);
            ffi::curl_easy_setopt(self.curl, opt::WRITEDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::HEADERFUNCTION, curl_header_fn);
            ffi::curl_easy_setopt(self.curl, opt::HEADERDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::PROGRESSFUNCTION, curl_progress_fn);
            ffi::curl_easy_setopt(self.curl, opt::PROGRESSDATA, progress_p);
        }

        let err = err::ErrCode(unsafe { ffi::curl_easy_perform(self.curl) });

        // If the request failed, abort here
        if !err.is_success() {
            return Err(err);
        }

        // Try to get the response code
        builder.code = try!(self.get_response_code());

        Ok(builder.build())
    }

    pub fn get_response_code(&self) -> Result<u32, err::ErrCode> {
        Ok(try!(self.get_info_long(info::RESPONSE_CODE)) as u32)
    }

    pub fn get_total_time(&self) -> Result<usize, err::ErrCode> {
        Ok(try!(self.get_info_long(info::TOTAL_TIME)) as usize)
    }

    fn get_info_long(&self, key: info::Key) -> Result<c_long, err::ErrCode> {
        let v: c_long = 0;
        let res = err::ErrCode(unsafe {
            ffi::curl_easy_getinfo(self.curl as *const _, key, &v)
        });

        if !res.is_success() {
            return Err(res);
        }

        Ok(v)
    }
}

#[inline]
fn global_init() {
    // Schedule curl to be cleaned up after we're done with this whole process
    static INIT: Once = ONCE_INIT;
    INIT.call_once(|| unsafe {
        assert_eq!(libc::atexit(cleanup), 0);
    });

    extern fn cleanup() {
        unsafe { ffi::curl_global_cleanup() }
    }
}

impl Drop for Easy {
    fn drop(&mut self) {
        unsafe { ffi::curl_easy_cleanup(self.curl) }
    }
}

/*
 *
 * TODO: Move this into handle
 *
 */

struct ResponseBuilder {
    code: u32,
    hdrs: HashMap<String,Vec<String>>,
    body: Vec<u8>
}

impl ResponseBuilder {
    fn new() -> ResponseBuilder {
        ResponseBuilder {
            code: 0,
            hdrs: HashMap::new(),
            body: Vec::new()
        }
    }

    fn add_header(&mut self, name: &str, val: &str) {
        // TODO: Reduce allocations
        use std::ascii::AsciiExt;
        let name = name.to_ascii_lowercase();

        let inserted = match self.hdrs.get_mut(&name) {
            Some(vals) => {
                vals.push(val.to_string());
                true
            }
            None => false
        };

        if !inserted {
            self.hdrs.insert(name, vec!(val.to_string()));
        }
    }

    fn build(self) -> Response {
        let ResponseBuilder { code, hdrs, body } = self;
        Response::new(code, hdrs, body)
    }
}

/*
 *
 * ===== Callbacks =====
 */

pub extern "C" fn curl_read_fn(p: *mut u8, size: size_t, nmemb: size_t, body: *mut Body) -> size_t {
    if body.is_null() {
        return 0;
    }

    let dst : &mut [u8] = unsafe { mem::transmute(raw::Slice { data: p, len: (size * nmemb) as usize } )};
    let body: &mut Body = unsafe { mem::transmute(body) };

    match body.read(dst.as_mut_slice()) {
        Ok(len) => len as size_t,
        Err(_) => consts::CURL_READFUNC_ABORT as size_t,
    }
}

pub extern "C" fn curl_write_fn(p: *mut u8, size: size_t, nmemb: size_t, resp: *mut ResponseBuilder) -> size_t {
    if !resp.is_null() {
        let builder: &mut ResponseBuilder = unsafe { mem::transmute(resp) };
        let chunk : &[u8] = unsafe { mem::transmute(raw::Slice { data: p, len: (size * nmemb) as usize } )};
        builder.body.push_all(chunk.as_slice());
    }

    size * nmemb
}

pub extern "C" fn curl_header_fn(p: *mut u8, size: size_t, nmemb: size_t, resp: &mut ResponseBuilder) -> size_t {
    // TODO: Skip the first call (it seems to be the status line)

    let vec : &[u8] = unsafe { mem::transmute(raw::Slice { data: p, len: (size * nmemb) as usize } )};

    match header::parse(vec.as_slice()) {
        Some((name, val)) => {
            resp.add_header(name, val);
        }
        None => {}
    }

    vec.len() as size_t
}

pub extern "C" fn curl_progress_fn(cb: *mut Box<ProgressCb>, dltotal: c_double, dlnow: c_double, ultotal: c_double, ulnow: c_double) -> c_int {
    #[inline]
    fn to_usize(v: c_double) -> usize {
        if v > 0.0 { v as usize } else { 0 }
    }

    if !cb.is_null() {
        let cb: &mut ProgressCb = unsafe { &mut **cb };
        (*cb)(to_usize(dltotal), to_usize(dlnow), to_usize(ultotal), to_usize(ulnow));
    }

    0
}
<|endoftext|>