<commit_before>#![allow(unused)]

use interpreter::ast::*;
use interpreter::tokenizer::*;

use std::collections::HashMap;

pub type Memory = HashMap<Ident, Expr>;

impl Expr {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        match self.node {
            Node::Ident(ref id) => {
                memory
                    .get(id)
                    .ok_or_else(|| {
                        self.debug.to_string() + ", but " + &id.0 + " has not been defined yet."
                    })
                    .map(|val| val.clone())
            }
            Node::Return(ref expr) => {
                let mut res = self.clone();
                res.node = Node::Return(Box::new(expr.run(memory)?));
                Ok(res)
            }
            Node::Op(ref operator) => operator.run(memory),
            Node::Function(ref function) => function.run(memory, Vec::new()),
            Node::If(ref if_stmt) => if_stmt.run(memory),
            Node::For(ref for_stmt) => for_stmt.run(memory),
            Node::While(ref while_stmt) => while_stmt.run(memory),
            _ => Ok(self.clone()),
        }
    }
}

/// avoids needlessly cloning an Expr if it is already resolved to
/// a primitive value. unfortunately, this requires passing in an
/// external storage variable for this case where the value has not
/// yet been resolved to a primitive, for lifetime reasons.
macro_rules! resolve {
    ($exp:ident, $memory:ident, $store:ident) => (
        match $exp.node {
            Node::Int(_) => $exp,
            Node::Float(_) => $exp,
            Node::Str(_) => $exp,
            Node::Bool(_) => $exp,
            _ => {$store = $exp.run($memory)?; &$store}
        }
    )
}

macro_rules! do_binary_op {
    ($op:tt, $memory:ident, $left:ident, $right:ident, $(($typeA:tt, $typeB:tt -> ($asType:tt:$asTypePrim:tt))),*; $(($typeA2:tt, $typeB2:tt -> ($asType2:tt))),*; _ => $defaultCase:expr) => ({
        let store1;
        let store2;
        let left_res = resolve!($left, $memory, store1);
        let right_res = resolve!($right, $memory, store2);
        match (&left_res.node, &right_res.node) {
            $(
                (&Node::$typeA(val1), &Node::$typeB(val2)) => {
                    Ok(Expr::new(Node::$asType((val1 as $asTypePrim) $op (val2 as $asTypePrim)), DebugInfo::none()))
                },
            )*
            $(
                (&Node::$typeA2(ref val1), &Node::$typeB2(ref val2)) => {
                    Ok(Expr::new(Node::$asType2(val1 $op val2), DebugInfo::none()))
                },
            )*
            _ => $defaultCase,
        }
    })
}

impl Operator {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        match *self {
            Operator::Assign(ref id, ref expr) => {
                let val = expr.run(memory)?;
                memory.insert(id.clone(), val);
                Ok(Expr::new(Node::Noop, expr.debug.clone()))
            }

            Operator::Call(ref id, ref args) => unimplemented!(),

            Operator::Add(ref left, ref right) => {
                do_binary_op!(+, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Sub(ref left, ref right) => {
                do_binary_op!(-, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Mul(ref left, ref right) => {
                do_binary_op!(*, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Div(ref left, ref right) => {
                do_binary_op!(/, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Mod(ref left, ref right) => {
                do_binary_op!(%, memory, left, right, (Int, Int -> (Int:i64));; _ => unimplemented!())
            }
            Operator::And(ref left, ref right) => {
                do_binary_op!(&&, memory, left, right, (Bool, Bool -> (Bool:bool));; _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to use logical AND on something which is not a boolean")?)
            }
            Operator::Or(ref left, ref right) => {
                do_binary_op!(||, memory, left, right, (Bool, Bool -> (Bool:bool));; _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to use logical OR on something which is not a boolean")?)
            }
            Operator::Less(ref left, ref right) => {
                do_binary_op!(<, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::LessOrEquals(ref left, ref right) => {
                do_binary_op!(<=, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::Greater(ref left, ref right) => {
                do_binary_op!(>, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::GreaterOrEquals(ref left, ref right) => {
                do_binary_op!(>=, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::Equals(ref left, ref right) => {
                do_binary_op!(==, memory, left, right,; (Int, Int -> (Bool)), (Float, Float -> (Bool)), (Str, Str -> (Bool)), (Bool, Bool -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::NotEquals(ref left, ref right) => {
                do_binary_op!(!=, memory, left, right,; (Int, Int -> (Bool)), (Float, Float -> (Bool)), (Str, Str -> (Bool)), (Bool, Bool -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }

            Operator::Negate(ref expr) => {
                let store;
                let expr_res = resolve!(expr, memory, store);
                match &expr_res.node {
                    &Node::Int(val) => Ok(Expr::new(Node::Int(-val), DebugInfo::none())),
                    &Node::Float(val) => Ok(Expr::new(Node::Float(-val), DebugInfo::none())),
                    _ => {
                        Err(
                            expr.debug.to_string() +
                                ", attempt to negate something which is not a number",
                        )?
                    }
                }
            }

            Operator::Not(ref expr) => {
                let store;
                let expr_res = resolve!(expr, memory, store);
                match &expr_res.node {
                    &Node::Bool(val) => Ok(Expr::new(Node::Bool(!val), DebugInfo::none())),
                    _ => {
                        Err(
                            expr.debug.to_string() +
                                ", attempt to use logical NOT on something which is not a boolean",
                        )?
                    }
                }
            }
        }
    }
}

/// get the list of visible identifiers at this scope level
fn get_scope(memory: &mut Memory) -> Vec<Ident> {
    memory.keys().cloned().collect()
}

/// remove any identifiers that were created during the scoped region
fn revert_scope(scope: Vec<Ident>, memory: &mut Memory) {
    memory.retain(|ident, _| scope.contains(ident));
}

fn revert_scope_after<T>(val: T, scope: Vec<Ident>, memory: &mut Memory) -> T {
    revert_scope(scope, memory);
    val
}

fn run_exprs(exprs: &Vec<Expr>, memory: &mut Memory) -> Result<Expr, String> {
    for mut expr in exprs {
        match expr.node {
            Node::Return(_) => expr.run(memory)?,
            _ => expr.run(memory)?,
        };
    }
    Ok(Expr::new(Node::Noop, DebugInfo::none()))
}

impl Function {
    fn run(&self, memory: &mut Memory, args: Vec<Expr>) -> Result<Expr, String> {
        if self.args.len() != args.len() {
            return Err(format!(
                "Function {} called with incorrect number of arguments. Expected {} but found {}.",
                self.name,
                self.args.len(),
                args.len()
            ))?;
        }
        let scope = get_scope(memory);
        for (id, val) in self.args.iter().zip(args) {
            memory.insert(id.clone(), val);
        }
        for mut expr in &self.body {
            match expr.run(memory)?.node {
                Node::Return(ret_expr) => return revert_scope_after(Ok(*ret_expr), scope, memory),
                _ => {}
            };
        }

        revert_scope(scope, memory);

        Ok(Expr::new(Node::Noop, DebugInfo::none()))
    }
}

impl If {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        let conditional = self.condition.run(memory)?;
        let conditional = match conditional.node {
            Node::Bool(bool_val) => bool_val,
            _ => Err("")?,
        };

        if conditional {
            run_exprs(&self.true_body, memory)
        } else {
            run_exprs(&self.else_body, memory)
        }
    }
}

impl For {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        unimplemented!();
    }
}

impl While {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        unimplemented!();
    }
}

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

    fn create_global(name: &str, memory: &mut Memory) {
        memory.insert(
            Ident(name.to_string()),
            Expr::new(Node::Noop, DebugInfo::none()),
        );
    }

    #[test]
    fn walk_assign() {
        let expr = Expr::parse("$someInt = 35").unwrap();
        let mut memory = &mut HashMap::new();

        // create $someInt outside the scope of the anonymous outer function that
        // Expr::parse returns, that way the effect of the assignment can be seen here.
        create_global("$someInt", memory);

        let result = expr.run(memory).unwrap();
        println!("{:#?}\n memory: {:#?}", result, memory);
    }

    #[test]
    fn walk_assign2() {
        let expr = Expr::parse("$otherInt = 35; $someInt = $otherInt + 2;").unwrap();
        let mut memory = &mut HashMap::new();

        // create $someInt outside the scope of the anonymous outer function that
        // Expr::parse returns, that way the effect of the assignment can be seen here.
        create_global("$someInt", memory);

        let result = expr.run(memory).unwrap();
        println!("{:#?}\n memory: {:#?}", result, memory);
    }

    #[test]
    #[should_panic]
    fn walk_assign_undefined() {
        let expr = Expr::parse("$someInt = 35; $otherInt = $someInt + $whatIsThis;").unwrap();
        let mut memory = &mut HashMap::new();
        let result = expr.run(memory).unwrap();
    }
}
<commit_msg>Small progress<commit_after>#![allow(unused)]

use interpreter::ast::*;
use interpreter::tokenizer::*;

use std::collections::HashMap;

pub type Memory = HashMap<Ident, Expr>;

impl Expr {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        match self.node {
            Node::Ident(ref id) => {
                memory
                    .get(id)
                    .ok_or_else(|| {
                        self.debug.to_string() + ", but " + &id.0 + " has not been defined yet."
                    })
                    .map(|val| val.clone())
            }
            Node::Return(ref expr) => {
                let mut res = self.clone();
                res.node = Node::Return(Box::new(expr.run(memory)?));
                Ok(res)
            }
            Node::Op(ref operator) => operator.run(memory),
            Node::Function(ref function) => function.run(memory, Vec::new()),
            Node::If(ref if_stmt) => if_stmt.run(memory),
            Node::For(ref for_stmt) => for_stmt.run(memory),
            Node::While(ref while_stmt) => while_stmt.run(memory),
            _ => Ok(self.clone()),
        }
    }
}

/// avoids needlessly cloning an Expr if it is already resolved to
/// a primitive value. unfortunately, this requires passing in an
/// external storage variable for this case where the value has not
/// yet been resolved to a primitive, for lifetime reasons.
macro_rules! resolve {
    ($exp:ident, $memory:ident, $store:ident) => (
        match $exp.node {
            Node::Int(_) => $exp,
            Node::Float(_) => $exp,
            Node::Str(_) => $exp,
            Node::Bool(_) => $exp,
            _ => {$store = $exp.run($memory)?; &$store}
        }
    )
}

macro_rules! do_binary_op {
    ($op:tt, $memory:ident, $left:ident, $right:ident, $(($typeA:tt, $typeB:tt -> ($asType:tt:$asTypePrim:tt))),*; $(($typeA2:tt, $typeB2:tt -> ($asType2:tt))),*; _ => $defaultCase:expr) => ({
        let store1;
        let store2;
        let left_res = resolve!($left, $memory, store1);
        let right_res = resolve!($right, $memory, store2);
        match (&left_res.node, &right_res.node) {
            $(
                (&Node::$typeA(val1), &Node::$typeB(val2)) => {
                    Ok(Expr::new(Node::$asType((val1 as $asTypePrim) $op (val2 as $asTypePrim)), DebugInfo::none()))
                },
            )*
            $(
                (&Node::$typeA2(ref val1), &Node::$typeB2(ref val2)) => {
                    Ok(Expr::new(Node::$asType2(val1 $op val2), DebugInfo::none()))
                },
            )*
            _ => $defaultCase,
        }
    })
}

impl Operator {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        match *self {
            Operator::Assign(ref id, ref expr) => {
                let val = expr.run(memory)?;
                memory.insert(id.clone(), val);
                Ok(Expr::new(Node::Noop, expr.debug.clone()))
            }

            Operator::Call(ref id, ref args) => unimplemented!(),

            Operator::Add(ref left, ref right) => {
                do_binary_op!(+, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Sub(ref left, ref right) => {
                do_binary_op!(-, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Mul(ref left, ref right) => {
                do_binary_op!(*, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Div(ref left, ref right) => {
                do_binary_op!(/, memory, left, right, (Int, Int -> (Int:i64)), (Float, Float -> (Float:f64)), (Float, Int -> (Float:f64)), (Int, Float -> (Float:f64));; _ => unimplemented!())
            }
            Operator::Mod(ref left, ref right) => {
                do_binary_op!(%, memory, left, right, (Int, Int -> (Int:i64));; _ => unimplemented!())
            }
            Operator::And(ref left, ref right) => {
                do_binary_op!(&&, memory, left, right, (Bool, Bool -> (Bool:bool));; _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to use logical AND on something which is not a boolean")?)
            }
            Operator::Or(ref left, ref right) => {
                do_binary_op!(||, memory, left, right, (Bool, Bool -> (Bool:bool));; _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to use logical OR on something which is not a boolean")?)
            }
            Operator::Less(ref left, ref right) => {
                do_binary_op!(<, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::LessOrEquals(ref left, ref right) => {
                do_binary_op!(<=, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::Greater(ref left, ref right) => {
                do_binary_op!(>, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::GreaterOrEquals(ref left, ref right) => {
                do_binary_op!(>=, memory, left, right, (Int, Int -> (Bool:i64)), (Float, Float -> (Bool:f64)), (Float, Int -> (Bool:f64)), (Int, Float -> (Bool:f64)); (Str, Str -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::Equals(ref left, ref right) => {
                do_binary_op!(==, memory, left, right,; (Int, Int -> (Bool)), (Float, Float -> (Bool)), (Str, Str -> (Bool)), (Bool, Bool -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }
            Operator::NotEquals(ref left, ref right) => {
                do_binary_op!(!=, memory, left, right,; (Int, Int -> (Bool)), (Float, Float -> (Bool)), (Str, Str -> (Bool)), (Bool, Bool -> (Bool)); _ => Err(
                            left.debug.to_string() + &right.debug.to_string() +
                            ", attempt to compare two values for equality which cannot be compared")?)
            }

            Operator::Negate(ref expr) => {
                let store;
                let expr_res = resolve!(expr, memory, store);
                match &expr_res.node {
                    &Node::Int(val) => Ok(Expr::new(Node::Int(-val), DebugInfo::none())),
                    &Node::Float(val) => Ok(Expr::new(Node::Float(-val), DebugInfo::none())),
                    _ => {
                        Err(
                            expr.debug.to_string() +
                                ", attempt to negate something which is not a number",
                        )?
                    }
                }
            }

            Operator::Not(ref expr) => {
                let store;
                let expr_res = resolve!(expr, memory, store);
                match &expr_res.node {
                    &Node::Bool(val) => Ok(Expr::new(Node::Bool(!val), DebugInfo::none())),
                    _ => {
                        Err(
                            expr.debug.to_string() +
                                ", attempt to use logical NOT on something which is not a boolean",
                        )?
                    }
                }
            }
        }
    }
}

/// get the list of visible identifiers at this scope level
fn get_scope(memory: &mut Memory) -> Vec<Ident> {
    memory.keys().cloned().collect()
}

/// remove any identifiers that were created during the scoped region
fn revert_scope(scope: Vec<Ident>, memory: &mut Memory) {
    memory.retain(|ident, _| scope.contains(ident));
}

fn revert_scope_after<T>(val: T, scope: Vec<Ident>, memory: &mut Memory) -> T {
    revert_scope(scope, memory);
    val
}

fn run_exprs(exprs: &Vec<Expr>, memory: &mut Memory) -> Result<Expr, String> {
    for mut expr in exprs {
        let expr = expr.run(memory)?;
        match expr.node {
            Node::Return(_) => return Ok(expr),
            _ => {}
        };
    }
    Ok(Expr::new(Node::Noop, DebugInfo::none()))
}

impl Function {
    fn run(&self, memory: &mut Memory, args: Vec<Expr>) -> Result<Expr, String> {
        if self.args.len() != args.len() {
            return Err(format!(
                "Function {} called with incorrect number of arguments. Expected {} but found {}.",
                self.name,
                self.args.len(),
                args.len()
            ))?;
        }
        let scope = get_scope(memory);
        for (id, val) in self.args.iter().zip(args) {
            memory.insert(id.clone(), val);
        }
        for mut expr in &self.body {
            match expr.run(memory)?.node {
                Node::Return(ret_expr) => return revert_scope_after(Ok(*ret_expr), scope, memory),
                _ => {}
            };
        }

        revert_scope(scope, memory);

        Ok(Expr::new(Node::Noop, DebugInfo::none()))
    }
}

impl If {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        let conditional = self.condition.run(memory)?;
        let conditional = match conditional.node {
            Node::Bool(bool_val) => bool_val,
            _ => Err("")?,
        };

        if conditional {
            run_exprs(&self.true_body, memory)
        } else {
            run_exprs(&self.else_body, memory)
        }
    }
}

impl For {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        unimplemented!();
    }
}

impl While {
    fn run(&self, memory: &mut Memory) -> Result<Expr, String> {
        unimplemented!();
    }
}

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

    fn create_global(name: &str, memory: &mut Memory) {
        memory.insert(
            Ident(name.to_string()),
            Expr::new(Node::Noop, DebugInfo::none()),
        );
    }

    #[test]
    fn walk_assign() {
        let expr = Expr::parse("$someInt = 35").unwrap();
        let mut memory = &mut HashMap::new();

        // create $someInt outside the scope of the anonymous outer function that
        // Expr::parse returns, that way the effect of the assignment can be seen here.
        create_global("$someInt", memory);

        let result = expr.run(memory).unwrap();
        println!("{:#?}\n memory: {:#?}", result, memory);
    }

    #[test]
    fn walk_assign2() {
        let expr = Expr::parse("$otherInt = 35; $someInt = $otherInt + 2;").unwrap();
        let mut memory = &mut HashMap::new();

        // create $someInt outside the scope of the anonymous outer function that
        // Expr::parse returns, that way the effect of the assignment can be seen here.
        create_global("$someInt", memory);

        let result = expr.run(memory).unwrap();
        println!("{:#?}\n memory: {:#?}", result, memory);
    }

    #[test]
    #[should_panic]
    fn walk_assign_undefined() {
        let expr = Expr::parse("$someInt = 35; $otherInt = $someInt + $whatIsThis;").unwrap();
        let mut memory = &mut HashMap::new();
        let result = expr.run(memory).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate regex;
extern crate toml;

use self::chrono::{Duration, NaiveTime};
use self::regex::Regex;
use self::toml::Value as Toml;

use constant::CONFIG_FILE_NAME;
use error::{CannotHappenError, CliError, ConfigError, ConfigErrorKind};
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{Error as IoError, Read};
use std::path::PathBuf;
use std::str::FromStr;

pub enum ConfigKey {
    BurnAfter,
    SweepPeriod,
    SweepTime,
}

impl ConfigKey {
    pub fn from<S: AsRef<str>>(key: S) -> Result<ConfigKey, ConfigError> {
        match key.as_ref().trim() {
            "burn.after"   => Ok(ConfigKey::BurnAfter),
            "sweep.period" => Ok(ConfigKey::SweepPeriod),
            "sweep.time"   => Ok(ConfigKey::SweepTime),
            _              => Err(ConfigError::new(ConfigErrorKind::InvalidKey)),
        }
    }

    fn to_str(&self) -> &str {
        match *self {
            ConfigKey::BurnAfter   => "burn.after",
            ConfigKey::SweepPeriod => "sweep.period",
            ConfigKey::SweepTime   => "sweep.time",
        }
    }

    fn to_pair(&self) -> (&str, &str) {
        let key = self
            .to_str()
            .split('.')
            .collect::<Vec<&str>>();
        (key[0], key[1]) // unsafe!
    }
}

pub struct Config {
    toml: Toml,
}

impl Config {
    fn path() -> PathBuf {
        path_buf![super::working_dir(), CONFIG_FILE_NAME]
    }

    pub fn exist() -> bool {
        Self::path().is_file()
    }

    fn to_string(&self) -> String {
        toml::encode_str(&self.toml)
    }

    pub fn create(&self) -> Result<(), IoError> {
        super::create_setting_file(Self::path(), self.to_string())
    }

    fn _new(toml: Toml) -> Self {
        Config { toml: toml }
    }

    pub fn default() -> Self {
        let mut config = BTreeMap::new();
        Self::insert_deeply(&mut config, &ConfigKey::BurnAfter  , "2 weeks".to_string());
        Self::insert_deeply(&mut config, &ConfigKey::SweepPeriod, "daily"  .to_string());
        Self::insert_deeply(&mut config, &ConfigKey::SweepTime  , "00:00"  .to_string());

        Self::_new(toml::encode(&config))
    }

    pub fn read() -> Result<Self, CliError> {
        let mut f = try!(File::open(Self::path()));

        let mut contents = String::new();
        try!(f.read_to_string(&mut contents));

        let result = contents
            .parse()
            .map_err(|e: Vec<_>| e.into_iter().find(|_| true));
        let toml = match result {
            Ok(toml)    => toml,
            Err(option) => match option {
                Some(e) => return Err(From::from(e)),
                None    => return Err(From::from(CannotHappenError)),
            },
        };

        Ok(Self::_new(toml))
    }

    fn get(key: &ConfigKey) -> Result<String, CliError> {
        let config = try!(Self::read()).toml;

        let result = config
            .lookup(key.to_str())
            .ok_or(ConfigError::new(match *key {
                ConfigKey::BurnAfter   => ConfigErrorKind::NotFoundBurnAfter,
                ConfigKey::SweepPeriod => unimplemented!(),
                ConfigKey::SweepTime   => unimplemented!(),
            }));
        let value = try!(result);

        value
            .as_str()
            .map(|v| v.to_string())
            .ok_or(From::from(ConfigError::new(ConfigErrorKind::NonStringValue)))
    }

    pub fn extract_burn_after() -> Result<Duration, CliError> {
        let key = ConfigKey::BurnAfter;

        let after       = try!(Self::get(&key));
        let after       = try!(Self::validate(&key, after));
        let after       = after.split(' ').collect::<Vec<&str>>();
        let (num, unit) = (after[0], after[1]);                    // unsafe!
        let num         = try!(num.parse::<u32>()) as i64;

        let duration = match unit {
            "day"  | "days"  => Duration::days(num),
            "week" | "weeks" => Duration::weeks(num),
            _                => return Err(From::from(CannotHappenError)),
        };

        Ok(duration)
    }

    pub fn set(mut self, key: &ConfigKey, value: String) -> Result<Self, ConfigError> {
        let mut config = match toml::decode::<BTreeMap<String, BTreeMap<String, String>>>(self.toml) {
            Some(decoded) => decoded,
            None          => return Err(ConfigError::new(ConfigErrorKind::Something)),
        };

        Self::insert_deeply(&mut config, key, value);

        self.toml = toml::encode(&config);

        Ok(self)
    }

    fn insert_deeply(table: &mut BTreeMap<String, BTreeMap<String, String>>, key: &ConfigKey, value: String) {
        let (first, second) = key.to_pair();

        let second = second.to_string();

        if table.contains_key(first) {
            table.get_mut(first).map(|e| e.insert(second, value));
        } else {
            let mut entry = BTreeMap::new();
            entry.insert(second, value);

            table.insert(first.to_string(), entry);
        }
    }

    pub fn validate<S: AsRef<str>>(key: &ConfigKey, value: S) -> Result<String, CliError> {
        let value = value.as_ref().trim();

        match *key {
            ConfigKey::BurnAfter => {
                let pair = try!(Regex::new(r"^(?P<num>\d+)\s?(?P<unit>days?|weeks?)$"))
                    .captures(value)
                    .map_or((None, None), |caps| (caps.name("num"), caps.name("unit")));
                let (num, unit) = match pair {
                    (Some(num), Some(unit)) => (num, unit),
                    _                       => return Err(From::from(ConfigError::new(ConfigErrorKind::BurnAfter))),
                };
                Ok(format!("{} {}", num, unit))
            },
            ConfigKey::SweepPeriod => {
                match value {
                    "daily" | "weekly" => Ok(value.to_string()),
                    _                  => Err(From::from(ConfigError::new(ConfigErrorKind::SweepPeriod))),
                }
            },
            ConfigKey::SweepTime => {
                match NaiveTime::from_str(format!("{}:00", value).as_ref()) {
                    Ok(_)  => Ok(value.to_string()),
                    // should set Err(e) to Error::cause()
                    Err(_) => Err(From::from(ConfigError::new(ConfigErrorKind::SweepTime))),
                }
            },
        }
    }
}
<commit_msg>[Refactoring] Use IntoIterator.next()<commit_after>extern crate chrono;
extern crate regex;
extern crate toml;

use self::chrono::{Duration, NaiveTime};
use self::regex::Regex;
use self::toml::Value as Toml;

use constant::CONFIG_FILE_NAME;
use error::{CannotHappenError, CliError, ConfigError, ConfigErrorKind};
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{Error as IoError, Read};
use std::path::PathBuf;
use std::str::FromStr;

pub enum ConfigKey {
    BurnAfter,
    SweepPeriod,
    SweepTime,
}

impl ConfigKey {
    pub fn from<S: AsRef<str>>(key: S) -> Result<ConfigKey, ConfigError> {
        match key.as_ref().trim() {
            "burn.after"   => Ok(ConfigKey::BurnAfter),
            "sweep.period" => Ok(ConfigKey::SweepPeriod),
            "sweep.time"   => Ok(ConfigKey::SweepTime),
            _              => Err(ConfigError::new(ConfigErrorKind::InvalidKey)),
        }
    }

    fn to_str(&self) -> &str {
        match *self {
            ConfigKey::BurnAfter   => "burn.after",
            ConfigKey::SweepPeriod => "sweep.period",
            ConfigKey::SweepTime   => "sweep.time",
        }
    }

    fn to_pair(&self) -> (&str, &str) {
        let key = self
            .to_str()
            .split('.')
            .collect::<Vec<&str>>();
        (key[0], key[1]) // unsafe!
    }
}

pub struct Config {
    toml: Toml,
}

impl Config {
    fn path() -> PathBuf {
        path_buf![super::working_dir(), CONFIG_FILE_NAME]
    }

    pub fn exist() -> bool {
        Self::path().is_file()
    }

    fn to_string(&self) -> String {
        toml::encode_str(&self.toml)
    }

    pub fn create(&self) -> Result<(), IoError> {
        super::create_setting_file(Self::path(), self.to_string())
    }

    fn _new(toml: Toml) -> Self {
        Config { toml: toml }
    }

    pub fn default() -> Self {
        let mut config = BTreeMap::new();
        Self::insert_deeply(&mut config, &ConfigKey::BurnAfter  , "2 weeks".to_string());
        Self::insert_deeply(&mut config, &ConfigKey::SweepPeriod, "daily"  .to_string());
        Self::insert_deeply(&mut config, &ConfigKey::SweepTime  , "00:00"  .to_string());

        Self::_new(toml::encode(&config))
    }

    pub fn read() -> Result<Self, CliError> {
        let mut f = try!(File::open(Self::path()));

        let mut contents = String::new();
        try!(f.read_to_string(&mut contents));

        let result = contents
            .parse()
            .map_err(|e: Vec<_>| e.into_iter().next());
        let toml = match result {
            Ok(toml)    => toml,
            Err(option) => match option {
                Some(e) => return Err(From::from(e)),
                None    => return Err(From::from(CannotHappenError)),
            },
        };

        Ok(Self::_new(toml))
    }

    fn get(key: &ConfigKey) -> Result<String, CliError> {
        let config = try!(Self::read()).toml;

        let result = config
            .lookup(key.to_str())
            .ok_or(ConfigError::new(match *key {
                ConfigKey::BurnAfter   => ConfigErrorKind::NotFoundBurnAfter,
                ConfigKey::SweepPeriod => unimplemented!(),
                ConfigKey::SweepTime   => unimplemented!(),
            }));
        let value = try!(result);

        value
            .as_str()
            .map(|v| v.to_string())
            .ok_or(From::from(ConfigError::new(ConfigErrorKind::NonStringValue)))
    }

    pub fn extract_burn_after() -> Result<Duration, CliError> {
        let key = ConfigKey::BurnAfter;

        let after       = try!(Self::get(&key));
        let after       = try!(Self::validate(&key, after));
        let after       = after.split(' ').collect::<Vec<&str>>();
        let (num, unit) = (after[0], after[1]);                    // unsafe!
        let num         = try!(num.parse::<u32>()) as i64;

        let duration = match unit {
            "day"  | "days"  => Duration::days(num),
            "week" | "weeks" => Duration::weeks(num),
            _                => return Err(From::from(CannotHappenError)),
        };

        Ok(duration)
    }

    pub fn set(mut self, key: &ConfigKey, value: String) -> Result<Self, ConfigError> {
        let mut config = match toml::decode::<BTreeMap<String, BTreeMap<String, String>>>(self.toml) {
            Some(decoded) => decoded,
            None          => return Err(ConfigError::new(ConfigErrorKind::Something)),
        };

        Self::insert_deeply(&mut config, key, value);

        self.toml = toml::encode(&config);

        Ok(self)
    }

    fn insert_deeply(table: &mut BTreeMap<String, BTreeMap<String, String>>, key: &ConfigKey, value: String) {
        let (first, second) = key.to_pair();

        let second = second.to_string();

        if table.contains_key(first) {
            table.get_mut(first).map(|e| e.insert(second, value));
        } else {
            let mut entry = BTreeMap::new();
            entry.insert(second, value);

            table.insert(first.to_string(), entry);
        }
    }

    pub fn validate<S: AsRef<str>>(key: &ConfigKey, value: S) -> Result<String, CliError> {
        let value = value.as_ref().trim();

        match *key {
            ConfigKey::BurnAfter => {
                let pair = try!(Regex::new(r"^(?P<num>\d+)\s?(?P<unit>days?|weeks?)$"))
                    .captures(value)
                    .map_or((None, None), |caps| (caps.name("num"), caps.name("unit")));
                let (num, unit) = match pair {
                    (Some(num), Some(unit)) => (num, unit),
                    _                       => return Err(From::from(ConfigError::new(ConfigErrorKind::BurnAfter))),
                };
                Ok(format!("{} {}", num, unit))
            },
            ConfigKey::SweepPeriod => {
                match value {
                    "daily" | "weekly" => Ok(value.to_string()),
                    _                  => Err(From::from(ConfigError::new(ConfigErrorKind::SweepPeriod))),
                }
            },
            ConfigKey::SweepTime => {
                match NaiveTime::from_str(format!("{}:00", value).as_ref()) {
                    Ok(_)  => Ok(value.to_string()),
                    // should set Err(e) to Error::cause()
                    Err(_) => Err(From::from(ConfigError::new(ConfigErrorKind::SweepTime))),
                }
            },
        }
    }
}
<|endoftext|>


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

//! The Rust prelude
//!
//! Because `std` is required by most serious Rust software, it is
//! imported at the topmost level of every crate by default, as if the
//! first line of each crate was
//!
//! ```ignore
//! extern crate std;
//! ```
//!
//! This means that the contents of std can be accessed from any context
//! with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`,
//! etc.
//!
//! Additionally, `std` contains a `prelude` module that reexports many of the
//! most common traits, types and functions. The contents of the prelude are
//! imported into every *module* by default.  Implicitly, all modules behave as if
//! they contained the following prologue:
//!
//! ```ignore
//! use std::prelude::v1::*;
//! ```
//!
//! The prelude is primarily concerned with exporting *traits* that are so
//! pervasive that it would be obnoxious to import for every use, particularly
//! those that define methods on primitive types.

#[stable]
pub mod v1;
<commit_msg>std: Fix missing stability on prelude<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Rust prelude
//!
//! Because `std` is required by most serious Rust software, it is
//! imported at the topmost level of every crate by default, as if the
//! first line of each crate was
//!
//! ```ignore
//! extern crate std;
//! ```
//!
//! This means that the contents of std can be accessed from any context
//! with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`,
//! etc.
//!
//! Additionally, `std` contains a `prelude` module that reexports many of the
//! most common traits, types and functions. The contents of the prelude are
//! imported into every *module* by default.  Implicitly, all modules behave as if
//! they contained the following prologue:
//!
//! ```ignore
//! use std::prelude::v1::*;
//! ```
//!
//! The prelude is primarily concerned with exporting *traits* that are so
//! pervasive that it would be obnoxious to import for every use, particularly
//! those that define methods on primitive types.

#![stable]

#[stable]
pub mod v1;
<|endoftext|>


<commit_before>//! System bindings for the Fortanix SGX platform
//!
//! This module contains the facade (aka platform-specific) implementations of
//! OS level functionality for Fortanix SGX.

#![allow(deprecated)]

use crate::io::ErrorKind;
use crate::os::raw::c_char;
use crate::sync::atomic::{AtomicBool, Ordering};

pub mod abi;
mod waitqueue;

pub mod alloc;
pub mod args;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rwlock;
pub mod stack_overflow;
pub mod thread;
pub mod thread_local;
pub mod time;
pub mod stdio;

pub use crate::sys_common::os_str_bytes as os_str;

#[cfg(not(test))]
pub fn init() {
}

/// This function is used to implement functionality that simply doesn't exist.
/// Programs relying on this functionality will need to deal with the error.
pub fn unsupported<T>() -> crate::io::Result<T> {
    Err(unsupported_err())
}

pub fn unsupported_err() -> crate::io::Error {
    crate::io::Error::new(ErrorKind::Other,
                   "operation not supported on SGX yet")
}

/// This function is used to implement various functions that doesn't exist,
/// but the lack of which might not be reason for error. If no error is
/// returned, the program might very well be able to function normally. This is
/// what happens when `SGX_INEFFECTIVE_ERROR` is set to `true`. If it is
/// `false`, the behavior is the same as `unsupported`.
pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
    static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false);
    if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) {
        Err(crate::io::Error::new(ErrorKind::Other,
                       "operation can't be trusted to have any effect on SGX"))
    } else {
        Ok(v)
    }
}

pub fn decode_error_kind(code: i32) -> ErrorKind {
    use fortanix_sgx_abi::Error;

    // FIXME: not sure how to make sure all variants of Error are covered
    if code == Error::NotFound as _ {
        ErrorKind::NotFound
    } else if code == Error::PermissionDenied as _ {
        ErrorKind::PermissionDenied
    } else if code == Error::ConnectionRefused as _ {
        ErrorKind::ConnectionRefused
    } else if code == Error::ConnectionReset as _ {
        ErrorKind::ConnectionReset
    } else if code == Error::ConnectionAborted as _ {
        ErrorKind::ConnectionAborted
    } else if code == Error::NotConnected as _ {
        ErrorKind::NotConnected
    } else if code == Error::AddrInUse as _ {
        ErrorKind::AddrInUse
    } else if code == Error::AddrNotAvailable as _ {
        ErrorKind::AddrNotAvailable
    } else if code == Error::BrokenPipe as _ {
        ErrorKind::BrokenPipe
    } else if code == Error::AlreadyExists as _ {
        ErrorKind::AlreadyExists
    } else if code == Error::WouldBlock as _ {
        ErrorKind::WouldBlock
    } else if code == Error::InvalidInput as _ {
        ErrorKind::InvalidInput
    } else if code == Error::InvalidData as _ {
        ErrorKind::InvalidData
    } else if code == Error::TimedOut as _ {
        ErrorKind::TimedOut
    } else if code == Error::WriteZero as _ {
        ErrorKind::WriteZero
    } else if code == Error::Interrupted as _ {
        ErrorKind::Interrupted
    } else if code == Error::Other as _ {
        ErrorKind::Other
    } else if code == Error::UnexpectedEof as _ {
        ErrorKind::UnexpectedEof
    } else {
        ErrorKind::Other
    }
}

// This enum is used as the storage for a bunch of types which can't actually
// exist.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum Void {}

pub unsafe fn strlen(mut s: *const c_char) -> usize {
    let mut n = 0;
    while *s != 0 {
        n += 1;
        s = s.offset(1);
    }
    return n
}

pub unsafe fn abort_internal() -> ! {
    abi::usercalls::exit(true)
}

// This function is needed by the panic runtime. The symbol is named in
// pre-link args for the target specification, so keep that in sync.
#[cfg(not(test))]
#[no_mangle]
// NB. used by both libunwind and libpanic_abort
pub unsafe extern "C" fn __rust_abort() {
    abort_internal();
}

pub fn hashmap_random_keys() -> (u64, u64) {
    fn rdrand64() -> u64 {
        unsafe {
            let mut ret: u64 = crate::mem::uninitialized();
            for _ in 0..10 {
                if crate::arch::x86_64::_rdrand64_step(&mut ret) == 1 {
                    return ret;
                }
            }
            rtabort!("Failed to obtain random data");
        }
    }
    (rdrand64(), rdrand64())
}

pub use crate::sys_common::{AsInner, FromInner, IntoInner};

pub trait TryIntoInner<Inner>: Sized {
    fn try_into_inner(self) -> Result<Inner, Self>;
}
<commit_msg>Remove last use of mem::uninitialized in SGX<commit_after>//! System bindings for the Fortanix SGX platform
//!
//! This module contains the facade (aka platform-specific) implementations of
//! OS level functionality for Fortanix SGX.

use crate::io::ErrorKind;
use crate::os::raw::c_char;
use crate::sync::atomic::{AtomicBool, Ordering};

pub mod abi;
mod waitqueue;

pub mod alloc;
pub mod args;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rwlock;
pub mod stack_overflow;
pub mod thread;
pub mod thread_local;
pub mod time;
pub mod stdio;

pub use crate::sys_common::os_str_bytes as os_str;

#[cfg(not(test))]
pub fn init() {
}

/// This function is used to implement functionality that simply doesn't exist.
/// Programs relying on this functionality will need to deal with the error.
pub fn unsupported<T>() -> crate::io::Result<T> {
    Err(unsupported_err())
}

pub fn unsupported_err() -> crate::io::Error {
    crate::io::Error::new(ErrorKind::Other,
                   "operation not supported on SGX yet")
}

/// This function is used to implement various functions that doesn't exist,
/// but the lack of which might not be reason for error. If no error is
/// returned, the program might very well be able to function normally. This is
/// what happens when `SGX_INEFFECTIVE_ERROR` is set to `true`. If it is
/// `false`, the behavior is the same as `unsupported`.
pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
    static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false);
    if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) {
        Err(crate::io::Error::new(ErrorKind::Other,
                       "operation can't be trusted to have any effect on SGX"))
    } else {
        Ok(v)
    }
}

pub fn decode_error_kind(code: i32) -> ErrorKind {
    use fortanix_sgx_abi::Error;

    // FIXME: not sure how to make sure all variants of Error are covered
    if code == Error::NotFound as _ {
        ErrorKind::NotFound
    } else if code == Error::PermissionDenied as _ {
        ErrorKind::PermissionDenied
    } else if code == Error::ConnectionRefused as _ {
        ErrorKind::ConnectionRefused
    } else if code == Error::ConnectionReset as _ {
        ErrorKind::ConnectionReset
    } else if code == Error::ConnectionAborted as _ {
        ErrorKind::ConnectionAborted
    } else if code == Error::NotConnected as _ {
        ErrorKind::NotConnected
    } else if code == Error::AddrInUse as _ {
        ErrorKind::AddrInUse
    } else if code == Error::AddrNotAvailable as _ {
        ErrorKind::AddrNotAvailable
    } else if code == Error::BrokenPipe as _ {
        ErrorKind::BrokenPipe
    } else if code == Error::AlreadyExists as _ {
        ErrorKind::AlreadyExists
    } else if code == Error::WouldBlock as _ {
        ErrorKind::WouldBlock
    } else if code == Error::InvalidInput as _ {
        ErrorKind::InvalidInput
    } else if code == Error::InvalidData as _ {
        ErrorKind::InvalidData
    } else if code == Error::TimedOut as _ {
        ErrorKind::TimedOut
    } else if code == Error::WriteZero as _ {
        ErrorKind::WriteZero
    } else if code == Error::Interrupted as _ {
        ErrorKind::Interrupted
    } else if code == Error::Other as _ {
        ErrorKind::Other
    } else if code == Error::UnexpectedEof as _ {
        ErrorKind::UnexpectedEof
    } else {
        ErrorKind::Other
    }
}

// This enum is used as the storage for a bunch of types which can't actually
// exist.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum Void {}

pub unsafe fn strlen(mut s: *const c_char) -> usize {
    let mut n = 0;
    while *s != 0 {
        n += 1;
        s = s.offset(1);
    }
    return n
}

pub unsafe fn abort_internal() -> ! {
    abi::usercalls::exit(true)
}

// This function is needed by the panic runtime. The symbol is named in
// pre-link args for the target specification, so keep that in sync.
#[cfg(not(test))]
#[no_mangle]
// NB. used by both libunwind and libpanic_abort
pub unsafe extern "C" fn __rust_abort() {
    abort_internal();
}

pub fn hashmap_random_keys() -> (u64, u64) {
    fn rdrand64() -> u64 {
        unsafe {
            let mut ret: u64 = 0;
            for _ in 0..10 {
                if crate::arch::x86_64::_rdrand64_step(&mut ret) == 1 {
                    return ret;
                }
            }
            rtabort!("Failed to obtain random data");
        }
    }
    (rdrand64(), rdrand64())
}

pub use crate::sys_common::{AsInner, FromInner, IntoInner};

pub trait TryIntoInner<Inner>: Sized {
    fn try_into_inner(self) -> Result<Inner, Self>;
}
<|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

use spaces::immix_space::block_info::BlockInfo;
use spaces::immix_space::block_allocator::BlockAllocator;
use spaces::immix_space::allocator::BlockTuple;
use spaces::immix_space::allocator::Allocator;

use std::collections::RingBuf;
use std::rc::Rc;
use std::cell::RefCell;

use constants::{BLOCK_SIZE, LINE_SIZE};

pub struct NormalAllocator {
    block_allocator: Rc<RefCell<BlockAllocator>>,
    unavailable_blocks: RingBuf<*mut BlockInfo>,
    recyclable_blocks: RingBuf<*mut BlockInfo>,
    current_block: Option<BlockTuple>,
}

impl NormalAllocator {
    pub fn new(block_allocator: Rc<RefCell<BlockAllocator>>) -> NormalAllocator {
        return NormalAllocator {
            block_allocator: block_allocator,
            unavailable_blocks: RingBuf::new(),
            recyclable_blocks: RingBuf::new(),
            current_block: None,
        };
    }

    pub fn set_recyclable_blocks(&mut self, blocks: RingBuf<*mut BlockInfo>) {
        self.recyclable_blocks = blocks;
    }
}

impl Allocator for NormalAllocator {
    fn get_all_blocks(&mut self) -> RingBuf<*mut BlockInfo> {
        return self.unavailable_blocks.drain()
                   .chain(self.recyclable_blocks.drain())
                   .chain(self.current_block.take().map(|b| b.0).into_iter())
                   .collect();
    }

    fn take_current_block(&mut self) -> Option<BlockTuple> {
        return self.current_block.take();
    }

    fn put_current_block(&mut self, block_tuple: BlockTuple) {
        self.current_block = Some(block_tuple);
    }

    fn get_new_block(&mut self) -> Option<BlockTuple> {
        debug!("Request new block");
        return self.block_allocator.borrow_mut()
                   .get_block()
                   .map(|b| unsafe{ (*b).set_allocated(); b })
                   .map(|block| (block, LINE_SIZE as u16, (BLOCK_SIZE - 1) as u16));
    }

    fn handle_no_hole(&mut self, size: usize) -> Option<BlockTuple> {
        if size >= LINE_SIZE {
            return None;
        }
        return match self.recyclable_blocks.pop_front() {
            None => None,
            Some(block) => match unsafe{ (*block).scan_block((LINE_SIZE - 1) as u16) } {
                None => {
                    self.handle_full_block(block);
                    self.handle_no_hole(size)
                },
                Some((low, high)) => self.scan_for_hole(size, (block, low, high))
                                         .or_else(|| self.handle_no_hole(size)),
            }
        };
    }

    fn handle_full_block(&mut self, block: *mut BlockInfo) {
        debug!("Push block {:p} into unavailable_blocks", block);
        self.unavailable_blocks.push_back(block);
    }
}
<commit_msg>Add rustdoc for allocator/normal_allocator.rs<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

use spaces::immix_space::block_info::BlockInfo;
use spaces::immix_space::block_allocator::BlockAllocator;
use spaces::immix_space::allocator::BlockTuple;
use spaces::immix_space::allocator::Allocator;

use std::collections::RingBuf;
use std::rc::Rc;
use std::cell::RefCell;

use constants::{BLOCK_SIZE, LINE_SIZE};

/// The `NormalAllocator` is the standard allocator to allocate objects within
/// the immix space.
///
/// Objects smaller than `MEDIUM_OBJECT` bytes are
pub struct NormalAllocator {
    /// The global `BlockAllocator` to get new blocks from.
    block_allocator: Rc<RefCell<BlockAllocator>>,

    /// The exhausted blocks.
    unavailable_blocks: RingBuf<*mut BlockInfo>,

    /// The blocks with holes to recycle before requesting new blocks..
    recyclable_blocks: RingBuf<*mut BlockInfo>,

    /// The current block to allocate from.
    current_block: Option<BlockTuple>,
}

impl NormalAllocator {
    /// Create a new `NormalAllocator` backed by the given `BlockAllocator`.
    pub fn new(block_allocator: Rc<RefCell<BlockAllocator>>) -> NormalAllocator {
        return NormalAllocator {
            block_allocator: block_allocator,
            unavailable_blocks: RingBuf::new(),
            recyclable_blocks: RingBuf::new(),
            current_block: None,
        };
    }

    /// Set the recyclable blocks.
    pub fn set_recyclable_blocks(&mut self, blocks: RingBuf<*mut BlockInfo>) {
        self.recyclable_blocks = blocks;
    }
}

impl Allocator for NormalAllocator {
    fn get_all_blocks(&mut self) -> RingBuf<*mut BlockInfo> {
        return self.unavailable_blocks.drain()
                   .chain(self.recyclable_blocks.drain())
                   .chain(self.current_block.take().map(|b| b.0).into_iter())
                   .collect();
    }

    fn take_current_block(&mut self) -> Option<BlockTuple> {
        return self.current_block.take();
    }

    fn put_current_block(&mut self, block_tuple: BlockTuple) {
        self.current_block = Some(block_tuple);
    }

    fn get_new_block(&mut self) -> Option<BlockTuple> {
        debug!("Request new block");
        return self.block_allocator.borrow_mut()
                   .get_block()
                   .map(|b| unsafe{ (*b).set_allocated(); b })
                   .map(|block| (block, LINE_SIZE as u16, (BLOCK_SIZE - 1) as u16));
    }

    fn handle_no_hole(&mut self, size: usize) -> Option<BlockTuple> {
        if size >= LINE_SIZE {
            return None;
        }
        return match self.recyclable_blocks.pop_front() {
            None => None,
            Some(block) => match unsafe{ (*block).scan_block((LINE_SIZE - 1) as u16) } {
                None => {
                    self.handle_full_block(block);
                    self.handle_no_hole(size)
                },
                Some((low, high)) => self.scan_for_hole(size, (block, low, high))
                                         .or_else(|| self.handle_no_hole(size)),
            }
        };
    }

    fn handle_full_block(&mut self, block: *mut BlockInfo) {
        debug!("Push block {:p} into unavailable_blocks", block);
        self.unavailable_blocks.push_back(block);
    }
}
<|endoftext|>


<commit_before>use serde::{
    Deserialize,
    Serialize,
};
use std::path::Path;

use serde_with::CommaSeparator;

use anyhow::Result;
use rnc_core::grouper;
use phf::phf_map;

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Precompute {
    pub id: usize,
    description: String,
    rna_type: String,
    has_coordinates: bool,
    so_rna_type: String,

    #[serde(with = "serde_with::rust::StringWithSeparator::<CommaSeparator>")]
    databases: Vec<String>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PrecomputeSummary {
    description: String,
    rna_type: String,
    has_coordinates: bool,
    databases: Vec<String>,
}

static SO_MAPPING: phf::Map<&'static str, &'static str> = phf_map! {
    "SO:0001263" => "SO:0000655",
    "SO:0001637" => "SO:0000252",
    "SO:0001427" => "SO:0000673",
    "SO:1001268" => "SO:0000673",
    "SO:0000122" => "SO:0000673",
    "SO:0005836" => "SO:0000673",
    "SO:0000185" => "SO:0000673",
    "SO:0000204" => "SO:0000673",
    "SO:0000140" => "SO:0000673",
    "SO:0000243" => "SO:0000673",
    "SO:0000205" => "SO:0000673",
    "SO:1001274" => "SO:0000673",
    "SO:0000726" => "SO:0000673",
    "SO:0000077" => "SO:0000673",
    "SO:0000836" => "SO:0000673",
    "SO:0000233" => "SO:0000673",
    "SO:0001267" => "SO:0000275",
};

impl Precompute {
    pub fn so_rna_type(&self) -> &str {
        let given: &str = &self.so_rna_type;
        SO_MAPPING.get(given).cloned().unwrap_or(given)
    }
}

impl From<Precompute> for PrecomputeSummary {
    fn from(pre: Precompute) -> PrecomputeSummary {
        Self {
            description: pre.description,
            rna_type: pre.rna_type.replace("_", " "),
            has_coordinates: pre.has_coordinates,
            databases: pre.databases,
        }
    }
}

impl Precompute {
    pub fn has_coordiante_string(self) -> String {
        match self.has_coordinates {
            true => String::from("True"),
            false => String::from("False"),
        }
    }
}

impl grouper::HasIndex for Precompute {
    fn index(&self) -> usize {
        self.id
    }
}

pub fn group(path: &Path, max: usize, output: &Path) -> Result<()> {
    grouper::group::<Precompute>(grouper::Criteria::ExactlyOne, &path, 1, max, &output)
}
<commit_msg>Move miRNA_primary_transcript_region to pre_miRNA<commit_after>use serde::{
    Deserialize,
    Serialize,
};
use std::path::Path;

use serde_with::CommaSeparator;

use anyhow::Result;
use rnc_core::grouper;
use phf::phf_map;

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Precompute {
    pub id: usize,
    description: String,
    rna_type: String,
    has_coordinates: bool,
    so_rna_type: String,

    #[serde(with = "serde_with::rust::StringWithSeparator::<CommaSeparator>")]
    databases: Vec<String>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PrecomputeSummary {
    description: String,
    rna_type: String,
    has_coordinates: bool,
    databases: Vec<String>,
}

static SO_MAPPING: phf::Map<&'static str, &'static str> = phf_map! {
    "SO:0001263" => "SO:0000655",
    "SO:0001637" => "SO:0000252",
    "SO:0001427" => "SO:0000673",
    "SO:1001268" => "SO:0000673",
    "SO:0000122" => "SO:0000673",
    "SO:0005836" => "SO:0000673",
    "SO:0000185" => "SO:0000673",
    "SO:0000204" => "SO:0000673",
    "SO:0000140" => "SO:0000673",
    "SO:0000243" => "SO:0000673",
    "SO:0000205" => "SO:0000673",
    "SO:1001274" => "SO:0000673",
    "SO:0000726" => "SO:0000673",
    "SO:0000077" => "SO:0000673",
    "SO:0000836" => "SO:0000673",
    "SO:0000233" => "SO:0000673",
    "SO:0001267" => "SO:0000275",
    "SO:0001243" => "SO:0001244",
};

impl Precompute {
    pub fn so_rna_type(&self) -> &str {
        let given: &str = &self.so_rna_type;
        SO_MAPPING.get(given).cloned().unwrap_or(given)
    }
}

impl From<Precompute> for PrecomputeSummary {
    fn from(pre: Precompute) -> PrecomputeSummary {
        Self {
            description: pre.description,
            rna_type: pre.rna_type.replace("_", " "),
            has_coordinates: pre.has_coordinates,
            databases: pre.databases,
        }
    }
}

impl Precompute {
    pub fn has_coordiante_string(self) -> String {
        match self.has_coordinates {
            true => String::from("True"),
            false => String::from("False"),
        }
    }
}

impl grouper::HasIndex for Precompute {
    fn index(&self) -> usize {
        self.id
    }
}

pub fn group(path: &Path, max: usize, output: &Path) -> Result<()> {
    grouper::group::<Precompute>(grouper::Criteria::ExactlyOne, &path, 1, max, &output)
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use super::ffi;
use libc::{c_int, c_uint, c_void, c_float, c_double};
use std::string::raw::from_buf;
use std::default::Default;

pub use ffi::TrackingState;
pub use ffi::FovPort;
pub use ffi::Sizei;
pub use ffi::RenderAPIConfig;
pub use ffi::RenderAPIConfigHeader;
pub use ffi::EyeRenderDesc;
pub use ffi::FrameTiming;
pub use ffi::Vector3f;
pub use ffi::Posef;

//-----------------------------------------------------------------------------------
// Enum wrappers
//-----------------------------------------------------------------------------------

#[deriving(PartialEq, Show)]
pub enum HmdType {
  HmdNone,
  HmdDK1,
  HmdDKHD,
  HmdDK2,
  HmdOther,
}
impl HmdType {
  fn from_ffi(c: c_uint) -> HmdType {
    match c {
      ffi::Hmd_None       => HmdNone,
      ffi::Hmd_DK1        => HmdDK1,
      ffi::Hmd_DKHD       => HmdDKHD,
      ffi::Hmd_DK2        => HmdDK2,
      _                   => HmdOther
    }
  }
  fn to_ffi(&self) -> c_uint {
    match *self {
      HmdNone             => ffi::Hmd_None,
      HmdDK1              => ffi::Hmd_DK1,
      HmdDKHD             => ffi::Hmd_DKHD,
      HmdDK2              => ffi::Hmd_DK2,
      HmdOther            => ffi::Hmd_Other
    }
  }
}

#[deriving(PartialEq, Show)]
pub enum EyeType {
  EyeL,
  EyeR,
}

impl EyeType {
  fn from_ffi(c: c_uint) -> EyeType {
    match c {
      ffi::Eye_Left  => EyeL,
      ffi::Eye_Right => EyeR,
      _ => panic!("Invalid eye type {}", c)
    }
  }
  fn to_ffi(&self) -> c_uint {
    match *self {
      EyeL => ffi::Eye_Left,
      EyeR => ffi::Eye_Right
    }
  }
}

//-----------------------------------------------------------------------------------
// Bitset wrappers
//-----------------------------------------------------------------------------------

pub struct BitMask {
  pub mask: c_uint,
}
impl BitMask {
  fn check_flag(&self, flag: c_uint) -> bool {
    self.mask & flag == flag
  }
  fn set_flag(&self, flag: c_uint, new_state: bool) -> BitMask {
    BitMask { mask:
      match new_state {
        true  => self.mask |  flag,
        false => self.mask & !flag,
      }
    }
  }
}

pub type HmdCaps = BitMask;
pub type DistortionCaps = BitMask;
pub type TrackingCaps = BitMask;

/*
/// Eventually, a type-safe approach like the following is better as the approach above.
/// However, since all the bitmasks are still subject to change in the SDK,
/// I chose a more low level approach for the time being...

#[deriving(Show)]
pub struct HmdCaps {
  flags: c_uint
}

impl HmdCaps {
  // non setable flags
  pub fn present(&self) -> bool {
    self.flags & ffi::HmdCap_Present == ffi::HmdCap_Present
  }
  pub fn available(&self) -> bool {
    self.flags & ffi::HmdCap_Available == ffi::HmdCap_Available
  }
  pub fn captured(&self) -> bool {
    self.flags & ffi::HmdCap_Captured == ffi::HmdCap_Captured
  }
  pub fn extend_desktop(&self) -> bool {
    self.flags & ffi::HmdCap_ExtendDesktop == ffi::HmdCap_ExtendDesktop
  }

  // setable flags
  pub fn no_mirror_to_window(&self) -> bool {
    self.flags & ffi::HmdCap_NoMirrorToWindow == ffi::HmdCap_NoMirrorToWindow
  }
  pub fn set_no_mirror_to_window(&self, flag: bool) -> HmdCaps {
    HmdCaps { flags:
      match flag {
        true  => self.flags |  ffi::HmdCap_NoMirrorToWindow,
        false => self.flags & !ffi::HmdCap_NoMirrorToWindow,
      }
    }
  }

  pub fn display_off(&self) -> bool {
    self.flags & ffi::HmdCap_DisplayOff == ffi::HmdCap_DisplayOff
  }
  pub fn set_display_off(&self, flag: bool) -> HmdCaps {
    HmdCaps { flags:
      match flag {
        true  => self.flags |  ffi::HmdCap_DisplayOff,
        false => self.flags & !ffi::HmdCap_DisplayOff,
      }
    }
  }

  pub fn low_persistance(&self) -> bool {
    self.flags & ffi::HmdCap_LowPersistence == ffi::HmdCap_LowPersistence
  }
  pub fn set_low_persistance(&self, flag: bool) -> HmdCaps {
    HmdCaps { flags:
      match flag {
        true  => self.flags |  ffi::HmdCap_LowPersistence,
        false => self.flags & !ffi::HmdCap_LowPersistence,
      }
    }
  }

  pub fn dynamic_prediction(&self) -> bool {
    self.flags & ffi::HmdCap_DynamicPrediction == ffi::HmdCap_DynamicPrediction
  }
  pub fn set_dynamic_prediction(&self, flag: bool) -> HmdCaps {
    HmdCaps { flags:
      match flag {
        true  => self.flags |  ffi::HmdCap_DynamicPrediction,
        false => self.flags & !ffi::HmdCap_DynamicPrediction,
      }
    }
  }

  pub fn no_vsync(&self) -> bool {
    self.flags & ffi::HmdCap_NoVSync == ffi::HmdCap_NoVSync
  }
  pub fn set_no_vsync(&self, flag: bool) -> HmdCaps {
    HmdCaps { flags:
      match flag {
        true  => self.flags |  ffi::HmdCap_NoVSync,
        false => self.flags & !ffi::HmdCap_NoVSync,
      }
    }
  }
}
*/

//-----------------------------------------------------------------------------------
// Wrapper for general OVR library
//-----------------------------------------------------------------------------------

pub struct Ovr;

impl Ovr {

  pub fn initialize() -> Option<Ovr> {
    unsafe {
      if ffi::ovr_Initialize() != 0i8 {
        Some(Ovr)
      } else {
        None
      }
    }
  }

  pub fn detect(&self) -> int {
    unsafe { ffi::ovrHmd_Detect() as int }
  }

  pub fn create_hmd(&self, index: int) -> Option<Hmd> {
    unsafe {
      let ptr = ffi::ovrHmd_Create(index as i32);
      if !ptr.is_null() {
        Some(Hmd{ ptr: ptr })
      } else {
        None
      }
    }
  }

  pub fn create_hmd_debug(&self, hmd_type: HmdType) -> Option<Hmd> {
    unsafe {
      let ptr = ffi::ovrHmd_CreateDebug(hmd_type.to_ffi());
      if !ptr.is_null() {
        Some(Hmd{ ptr: ptr })
      } else {
        None
      }
    }
  }

}

impl Drop for Ovr {
  fn drop(&mut self) {
    unsafe { ffi::ovr_Shutdown(); }
  }
}

//-----------------------------------------------------------------------------------
// Wrapper for HMD
//-----------------------------------------------------------------------------------

pub struct Hmd {
  ptr: *mut ffi::Hmd
}

impl Hmd {

  pub fn get_last_error(&self) -> Option<String> {
    unsafe {
      let ptr = ffi::ovrHmd_GetLastError(self.ptr);
      match ptr.is_null() {
        true  => None,
        false => Some(from_buf(ptr as *const u8)),
      }
    }
  }

  /// TODO
  pub fn attach_to_window() {
    unimplemented!()
  }

  pub fn get_enabled_caps(&self) -> HmdCaps {
    unsafe {
      let flags = ffi::ovrHmd_GetEnabledCaps(self.ptr);
      HmdCaps{ mask: flags }
    }
  }

  pub fn set_enabled_caps(&self, caps: HmdCaps) {
    unsafe {
      let flags = caps.mask;
      ffi::ovrHmd_SetEnabledCaps(self.ptr, flags);
    }
  }

  pub fn configure_tracking(&self, supported_tracking_caps: TrackingCaps, required_tracking_caps: TrackingCaps) -> bool {
    unsafe {
      let ovr_bool = ffi::ovrHmd_ConfigureTracking(
        self.ptr, supported_tracking_caps.mask, required_tracking_caps.mask
      );
      ovr_bool != 0i8
    }
  }

  pub fn recenter_pose(&self) {
    unsafe {
      ffi::ovrHmd_RecenterPose(self.ptr);
    }
  }

  pub fn get_tracking_state(&self, abs_time: f64) -> TrackingState {
    unsafe {
      ffi::ovrHmd_GetTrackingState(self.ptr, abs_time)
    }
  }

  pub fn get_fov_texture_size(&self, eye: EyeType, fov: FovPort, pixels_per_display_pixel: f32) -> Sizei {
    unsafe {
      ffi::ovrHmd_GetFovTextureSize(self.ptr, eye.to_ffi(), fov, pixels_per_display_pixel)
    }
  }

  pub fn configure_rendering(
    &self,
    api_config: RenderAPIConfig,
    distortion_caps: DistortionCaps,
    eye_fov_in: [FovPort, ..2],
  ) -> [EyeRenderDesc, ..2] {
    unsafe {
      let eye_fov_in_ptr: *const FovPort = &eye_fov_in[0];
      let mut eye_render_desc_out: [EyeRenderDesc, ..2] = [Default::default(), Default::default()];
      let eye_render_desc_out_ptr: *mut EyeRenderDesc = &mut eye_render_desc_out[0];
      ffi::ovrHmd_ConfigureRendering(self.ptr, &api_config, distortion_caps.mask, eye_fov_in_ptr, eye_render_desc_out_ptr);
      eye_render_desc_out
    }
  }

  pub fn begin_frame(&self, frame_index: i32) -> FrameTiming {
    unsafe {
      ffi::ovrHmd_BeginFrame(self.ptr, frame_index as c_uint)
    }
  }

  pub fn get_eye_poses(&self, frame_index: i32, hmd_to_eye_view_offset: [Vector3f, ..2]) {
    unsafe {
      let mut out_eye_poses: [Posef, ..2] = [Default::default(), Default::default()];
      let out_eye_poses_ptr: *mut Posef = &mut out_eye_poses[0];
      let mut out_hmd_tracking_state: TrackingState = Default::default();
      ffi::ovrHmd_GetEyePoses(self.ptr,
                              frame_index as c_uint,
                              &hmd_to_eye_view_offset[0],
                              out_eye_poses_ptr,
                              &mut out_hmd_tracking_state);
    }
  }

/*
  pub fn ovrHmd_GetEyePoses(hmd: *mut Hmd,
                            frameIndex: c_uint,
                            hmdToEyeViewOffset: *mut Posef,
                            outEyePoses: *mut Posef,
                            outHmdTrackingState: *mut TrackingState);

    pub fn get_sensor_state(&self, abs_time: f64) -> SensorState {
        unsafe {
            SensorState::from_ll(ll::ovrHmd_GetSensorState(self.ptr, abs_time))
        }
    }

    pub fn get_sensor_description(&self) -> Option<SensorDescription> {
        unsafe {
            let mut c_desc = ll::SensorDesc {
                vendor_id: 0,
                product_id: 0,
                serial_number: [0,.. 24]
            };

            if !ll::ovrHmd_GetSensorDesc(self.ptr, &mut c_desc as *mut ll::SensorDesc) {
                None
            } else {
                Some(SensorDescription::from_ll(c_desc))
            }
        }
    }

    pub fn get_description(&self) -> HmdDescription {
        unsafe {
            let mut c_desc = Default::default();
            ll::ovrHmd_GetDesc(self.ptr, &mut c_desc);
            HmdDescription::from_ll(c_desc)
        }
    }

    pub fn get_fov_texture_size(&self,
                                eye: EyeType,
                                fov: FovPort,
                                pixels_per_display_pixel: f32) -> ll::Sizei {
        unsafe {
            ll::ovrHmd_GetFovTextureSize(self.ptr,
                                         eye.to_ll(),
                                         fov.to_ll(),
                                         pixels_per_display_pixel)
        }
    }

    pub fn configure_rendering<RC: ToRenderConfig>(&self,
                               api_config: &RC,
                               cap: DistortionCapabilities,
                               eye_fov: PerEye<FovPort>) -> Option<PerEye<EyeRenderDescriptor>> {
        unsafe {
            let mut out: PerEye<ll::EyeRenderDesc> = PerEye::new(Default::default(),
                                                                 Default::default());
            let was_started = ll::ovrHmd_ConfigureRendering(
                self.ptr,
                &api_config.to_render_config(),
                cap.flags,
                eye_fov.map(|_, d| d.to_ll()).ptr(),
                out.mut_ptr()
            );

            if was_started {
                Some(out.map(|_, d| EyeRenderDescriptor::from_ll(d)))
            } else {
                None
            }
        }
    }

    pub fn begin_frame(&self, frame_index: uint) -> FrameTiming {
        unsafe {
            FrameTiming::from_ll(
                ll::ovrHmd_BeginFrame(self.ptr, frame_index as c_uint)
            )
        }
    }

    pub fn end_frame(&self) {
        unsafe {
            ll::ovrHmd_EndFrame(self.ptr);
        }
    }

    pub fn begin_eye_render(&self, eye: EyeType) -> Pose {
        unsafe {
            Pose::from_ll(ll::ovrHmd_BeginEyeRender(self.ptr, eye.to_ll()))
        }
    }

    pub fn end_eye_render<T: ToTexture>(&self,
                                        eye: EyeType,
                                        pose: Pose,
                                        texture: &T) {
        unsafe {
            ll::ovrHmd_EndEyeRender(self.ptr,
                                    eye.to_ll(),
                                    pose.to_ll(),
                                    &texture.to_texture());
        }
    }
    */
}

impl Drop for Hmd {
  fn drop(&mut self) {
    unsafe {ffi::ovrHmd_Destroy(self.ptr)}
  }
}

<commit_msg>few more functions<commit_after>#![allow(dead_code)]

use super::ffi;
use libc::{c_int, c_uint, c_void, c_float, c_double};
use std::string::raw::from_buf;
use std::default::Default;

pub use ffi::TrackingState;
pub use ffi::FovPort;
pub use ffi::Sizei;
pub use ffi::RenderAPIConfig;
pub use ffi::RenderAPIConfigHeader;
pub use ffi::EyeRenderDesc;
pub use ffi::FrameTiming;
pub use ffi::Vector3f;
pub use ffi::Posef;
pub use ffi::Matrix4f;

//-----------------------------------------------------------------------------------
// Enum wrappers
//-----------------------------------------------------------------------------------

#[deriving(PartialEq, Show)]
pub enum HmdType {
  HmdNone,
  HmdDK1,
  HmdDKHD,
  HmdDK2,
  HmdOther,
}
impl HmdType {
  fn from_ffi(c: c_uint) -> HmdType {
    match c {
      ffi::Hmd_None       => HmdNone,
      ffi::Hmd_DK1        => HmdDK1,
      ffi::Hmd_DKHD       => HmdDKHD,
      ffi::Hmd_DK2        => HmdDK2,
      _                   => HmdOther
    }
  }
  fn to_ffi(&self) -> c_uint {
    match *self {
      HmdNone             => ffi::Hmd_None,
      HmdDK1              => ffi::Hmd_DK1,
      HmdDKHD             => ffi::Hmd_DKHD,
      HmdDK2              => ffi::Hmd_DK2,
      HmdOther            => ffi::Hmd_Other
    }
  }
}

#[deriving(PartialEq, Show)]
pub enum EyeType {
  EyeL,
  EyeR,
}

impl EyeType {
  fn from_ffi(c: c_uint) -> EyeType {
    match c {
      ffi::Eye_Left  => EyeL,
      ffi::Eye_Right => EyeR,
      _ => panic!("Invalid eye type {}", c)
    }
  }
  fn to_ffi(&self) -> c_uint {
    match *self {
      EyeL => ffi::Eye_Left,
      EyeR => ffi::Eye_Right
    }
  }
}

//-----------------------------------------------------------------------------------
// Bitset wrappers
//-----------------------------------------------------------------------------------

pub struct BitMask {
  pub mask: c_uint,
}
impl BitMask {
  fn check_flag(&self, flag: c_uint) -> bool {
    self.mask & flag == flag
  }
  fn set_flag(&self, flag: c_uint, new_state: bool) -> BitMask {
    BitMask { mask:
      match new_state {
        true  => self.mask |  flag,
        false => self.mask & !flag,
      }
    }
  }
}

pub type HmdCaps = BitMask;
pub type DistortionCaps = BitMask;
pub type TrackingCaps = BitMask;

/*
/// Eventually, a type-safe approach like the following is better as the approach above.
/// However, since all the bitmasks are still subject to change in the SDK,
/// I chose a more low level approach for the time being...

#[deriving(Show)]
pub struct HmdCaps {
  flags: c_uint
}

impl HmdCaps {
  // non setable flags
  pub fn present(&self) -> bool {
    self.flags & ffi::HmdCap_Present == ffi::HmdCap_Present
  }
  pub fn available(&self) -> bool {
    self.flags & ffi::HmdCap_Available == ffi::HmdCap_Available
  }
  pub fn captured(&self) -> bool {
    self.flags & ffi::HmdCap_Captured == ffi::HmdCap_Captured
  }
  pub fn extend_desktop(&self) -> bool {
    self.flags & ffi::HmdCap_ExtendDesktop == ffi::HmdCap_ExtendDesktop
  }

  // setable flags
  pub fn no_mirror_to_window(&self) -> bool {
    self.flags & ffi::HmdCap_NoMirrorToWindow == ffi::HmdCap_NoMirrorToWindow
  }
  pub fn set_no_mirror_to_window(&self, flag: bool) -> HmdCaps {
    HmdCaps { flags:
      match flag {
        true  => self.flags |  ffi::HmdCap_NoMirrorToWindow,
        false => self.flags & !ffi::HmdCap_NoMirrorToWindow,
      }
    }
  }

  pub fn display_off(&self) -> bool {
    self.flags & ffi::HmdCap_DisplayOff == ffi::HmdCap_DisplayOff
  }
  pub fn set_display_off(&self, flag: bool) -> HmdCaps {
    HmdCaps { flags:
      match flag {
        true  => self.flags |  ffi::HmdCap_DisplayOff,
        false => self.flags & !ffi::HmdCap_DisplayOff,
      }
    }
  }

  pub fn low_persistance(&self) -> bool {
    self.flags & ffi::HmdCap_LowPersistence == ffi::HmdCap_LowPersistence
  }
  pub fn set_low_persistance(&self, flag: bool) -> HmdCaps {
    HmdCaps { flags:
      match flag {
        true  => self.flags |  ffi::HmdCap_LowPersistence,
        false => self.flags & !ffi::HmdCap_LowPersistence,
      }
    }
  }

  pub fn dynamic_prediction(&self) -> bool {
    self.flags & ffi::HmdCap_DynamicPrediction == ffi::HmdCap_DynamicPrediction
  }
  pub fn set_dynamic_prediction(&self, flag: bool) -> HmdCaps {
    HmdCaps { flags:
      match flag {
        true  => self.flags |  ffi::HmdCap_DynamicPrediction,
        false => self.flags & !ffi::HmdCap_DynamicPrediction,
      }
    }
  }

  pub fn no_vsync(&self) -> bool {
    self.flags & ffi::HmdCap_NoVSync == ffi::HmdCap_NoVSync
  }
  pub fn set_no_vsync(&self, flag: bool) -> HmdCaps {
    HmdCaps { flags:
      match flag {
        true  => self.flags |  ffi::HmdCap_NoVSync,
        false => self.flags & !ffi::HmdCap_NoVSync,
      }
    }
  }
}
*/

//-----------------------------------------------------------------------------------
// Wrapper for general OVR library
//-----------------------------------------------------------------------------------

pub struct Ovr;

impl Ovr {

  pub fn initialize() -> Option<Ovr> {
    unsafe {
      if ffi::ovr_Initialize() != 0i8 {
        Some(Ovr)
      } else {
        None
      }
    }
  }

  pub fn detect(&self) -> int {
    unsafe { ffi::ovrHmd_Detect() as int }
  }

  pub fn create_hmd(&self, index: int) -> Option<Hmd> {
    unsafe {
      let ptr = ffi::ovrHmd_Create(index as i32);
      if !ptr.is_null() {
        Some(Hmd{ ptr: ptr })
      } else {
        None
      }
    }
  }

  pub fn create_hmd_debug(&self, hmd_type: HmdType) -> Option<Hmd> {
    unsafe {
      let ptr = ffi::ovrHmd_CreateDebug(hmd_type.to_ffi());
      if !ptr.is_null() {
        Some(Hmd{ ptr: ptr })
      } else {
        None
      }
    }
  }

}

impl Drop for Ovr {
  fn drop(&mut self) {
    unsafe { ffi::ovr_Shutdown(); }
  }
}

//-----------------------------------------------------------------------------------
// Wrapper for HMD
//-----------------------------------------------------------------------------------

pub struct Hmd {
  ptr: *mut ffi::Hmd
}

impl Hmd {

  pub fn get_last_error(&self) -> Option<String> {
    unsafe {
      let ptr = ffi::ovrHmd_GetLastError(self.ptr);
      match ptr.is_null() {
        true  => None,
        false => Some(from_buf(ptr as *const u8)),
      }
    }
  }

  /// TODO
  pub fn attach_to_window() {
    unimplemented!()
  }

  pub fn get_enabled_caps(&self) -> HmdCaps {
    unsafe {
      let flags = ffi::ovrHmd_GetEnabledCaps(self.ptr);
      HmdCaps{ mask: flags }
    }
  }

  pub fn set_enabled_caps(&self, caps: HmdCaps) {
    unsafe {
      let flags = caps.mask;
      ffi::ovrHmd_SetEnabledCaps(self.ptr, flags);
    }
  }

  pub fn configure_tracking(&self, supported_tracking_caps: TrackingCaps, required_tracking_caps: TrackingCaps) -> bool {
    unsafe {
      let ovr_bool = ffi::ovrHmd_ConfigureTracking(
        self.ptr, supported_tracking_caps.mask, required_tracking_caps.mask
      );
      ovr_bool != 0i8
    }
  }

  pub fn recenter_pose(&self) {
    unsafe {
      ffi::ovrHmd_RecenterPose(self.ptr);
    }
  }

  pub fn get_tracking_state(&self, abs_time: f64) -> TrackingState {
    unsafe {
      ffi::ovrHmd_GetTrackingState(self.ptr, abs_time)
    }
  }

  pub fn get_fov_texture_size(&self, eye: EyeType, fov: FovPort, pixels_per_display_pixel: f32) -> Sizei {
    unsafe {
      ffi::ovrHmd_GetFovTextureSize(self.ptr, eye.to_ffi(), fov, pixels_per_display_pixel)
    }
  }

  pub fn configure_rendering(
    &self,
    api_config: RenderAPIConfig,
    distortion_caps: DistortionCaps,
    eye_fov_in: [FovPort, ..2],
  ) -> [EyeRenderDesc, ..2] {
    unsafe {
      let eye_fov_in_ptr: *const FovPort = &eye_fov_in[0];
      let mut eye_render_desc_out: [EyeRenderDesc, ..2] = [Default::default(), Default::default()];
      let eye_render_desc_out_ptr: *mut EyeRenderDesc = &mut eye_render_desc_out[0];
      ffi::ovrHmd_ConfigureRendering(self.ptr, &api_config, distortion_caps.mask, eye_fov_in_ptr, eye_render_desc_out_ptr);
      eye_render_desc_out
    }
  }

  pub fn begin_frame(&self, frame_index: i32) -> FrameTiming {
    unsafe {
      ffi::ovrHmd_BeginFrame(self.ptr, frame_index as c_uint)
    }
  }

  pub fn get_eye_poses(&self, frame_index: i32, hmd_to_eye_view_offset: [Vector3f, ..2]) {
    unsafe {
      let mut out_eye_poses: [Posef, ..2] = [Default::default(), Default::default()];
      let out_eye_poses_ptr: *mut Posef = &mut out_eye_poses[0];
      let mut out_hmd_tracking_state: TrackingState = Default::default();
      ffi::ovrHmd_GetEyePoses(self.ptr,
                              frame_index as c_uint,
                              &hmd_to_eye_view_offset[0],
                              out_eye_poses_ptr,
                              &mut out_hmd_tracking_state);
    }
  }

  pub fn get_render_desc(&self, eye: EyeType, fov: FovPort) -> EyeRenderDesc {
    unsafe {
      ffi::ovrHmd_GetRenderDesc(self.ptr, eye.to_ffi(), fov)
    }
  }

  pub fn get_frame_timing(&self, frame_index: i32) -> FrameTiming {
    unsafe {
      ffi::ovrHmd_GetFrameTiming(self.ptr, frame_index as c_uint)
    }
  }

  pub fn begin_frame_timing(&self, frame_index: i32) -> FrameTiming {
    unsafe {
      ffi::ovrHmd_BeginFrameTiming(self.ptr, frame_index as c_uint)
    }
  }

  pub fn end_frame_timing(&self) {
    unsafe {
      ffi::ovrHmd_EndFrameTiming(self.ptr);
    }
  }

  pub fn reset_frame_timing(&self, frame_index: i32) {
    unsafe {
      ffi::ovrHmd_ResetFrameTiming(self.ptr, frame_index as c_uint);
    }
  }

  pub fn get_eye_timewarp_matrices(&self, eye: EyeType, render_pose: Posef) -> Matrix4f {
    unsafe {
      let mut twm_out = Matrix4f{ M: [[0f32 as c_float, ..4], ..4] };
      ffi::ovrHmd_GetEyeTimewarpMatrices(self.ptr, eye.to_ffi(), render_pose, &mut twm_out);
      twm_out
    }
  }

/*

    pub fn get_sensor_state(&self, abs_time: f64) -> SensorState {
        unsafe {
            SensorState::from_ll(ll::ovrHmd_GetSensorState(self.ptr, abs_time))
        }
    }

    pub fn get_sensor_description(&self) -> Option<SensorDescription> {
        unsafe {
            let mut c_desc = ll::SensorDesc {
                vendor_id: 0,
                product_id: 0,
                serial_number: [0,.. 24]
            };

            if !ll::ovrHmd_GetSensorDesc(self.ptr, &mut c_desc as *mut ll::SensorDesc) {
                None
            } else {
                Some(SensorDescription::from_ll(c_desc))
            }
        }
    }

    pub fn get_description(&self) -> HmdDescription {
        unsafe {
            let mut c_desc = Default::default();
            ll::ovrHmd_GetDesc(self.ptr, &mut c_desc);
            HmdDescription::from_ll(c_desc)
        }
    }

    pub fn get_fov_texture_size(&self,
                                eye: EyeType,
                                fov: FovPort,
                                pixels_per_display_pixel: f32) -> ll::Sizei {
        unsafe {
            ll::ovrHmd_GetFovTextureSize(self.ptr,
                                         eye.to_ll(),
                                         fov.to_ll(),
                                         pixels_per_display_pixel)
        }
    }

    pub fn configure_rendering<RC: ToRenderConfig>(&self,
                               api_config: &RC,
                               cap: DistortionCapabilities,
                               eye_fov: PerEye<FovPort>) -> Option<PerEye<EyeRenderDescriptor>> {
        unsafe {
            let mut out: PerEye<ll::EyeRenderDesc> = PerEye::new(Default::default(),
                                                                 Default::default());
            let was_started = ll::ovrHmd_ConfigureRendering(
                self.ptr,
                &api_config.to_render_config(),
                cap.flags,
                eye_fov.map(|_, d| d.to_ll()).ptr(),
                out.mut_ptr()
            );

            if was_started {
                Some(out.map(|_, d| EyeRenderDescriptor::from_ll(d)))
            } else {
                None
            }
        }
    }

    pub fn begin_frame(&self, frame_index: uint) -> FrameTiming {
        unsafe {
            FrameTiming::from_ll(
                ll::ovrHmd_BeginFrame(self.ptr, frame_index as c_uint)
            )
        }
    }

    pub fn end_frame(&self) {
        unsafe {
            ll::ovrHmd_EndFrame(self.ptr);
        }
    }

    pub fn begin_eye_render(&self, eye: EyeType) -> Pose {
        unsafe {
            Pose::from_ll(ll::ovrHmd_BeginEyeRender(self.ptr, eye.to_ll()))
        }
    }

    pub fn end_eye_render<T: ToTexture>(&self,
                                        eye: EyeType,
                                        pose: Pose,
                                        texture: &T) {
        unsafe {
            ll::ovrHmd_EndEyeRender(self.ptr,
                                    eye.to_ll(),
                                    pose.to_ll(),
                                    &texture.to_texture());
        }
    }
    */
}

impl Drop for Hmd {
  fn drop(&mut self) {
    unsafe {ffi::ovrHmd_Destroy(self.ptr)}
  }
}

<|endoftext|>