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

use proc_macro2::TokenStream;
use quote::quote;
use std::path::PathBuf;

/// The strategy used to generate, and to find generated, files.
/// As standard, these are based off the OUT_DIR set by Cargo,
/// but our code can't assume it can read OUT_DIR as it may
/// be running in the rust-analyzer proc macro server where it's
/// not available. We need to give provision for custom locations
/// and we need our code generator build script to be able to pass
/// locations through to the proc macro by env vars.
///
/// On the whole this class concerns itself with directory names
/// and allows the actual file name to be determined elsewhere
/// (based on a hash of the contents of `include_cpp!`.) But
/// some types of build system need to know the precise file _name_
/// produced by the codegen phase and passed into the macro phase,
/// so we have a `AUTOCXX_RS_FILE` option for that.
pub enum FileLocationStrategy {
    Custom(PathBuf),
    FromAutocxxRsFile(PathBuf),
    FromAutocxxRs(PathBuf),
    FromOutDir(PathBuf),
    UnknownMaybeFromOutdir,
}

static BUILD_DIR_NAME: &str = "autocxx-build-dir";
static RS_DIR_NAME: &str = "rs";
static AUTOCXX_RS: &str = "AUTOCXX_RS";
static AUTOCXX_RS_FILE: &str = "AUTOCXX_RS_FILE";

impl FileLocationStrategy {
    pub fn new() -> Self {
        match std::env::var_os(AUTOCXX_RS_FILE) {
            Some(of) => FileLocationStrategy::FromAutocxxRsFile(PathBuf::from(of)),
            None => match std::env::var_os(AUTOCXX_RS) {
                None => match std::env::var_os("OUT_DIR") {
                    None => FileLocationStrategy::UnknownMaybeFromOutdir,
                    Some(od) => FileLocationStrategy::FromOutDir(PathBuf::from(od)),
                },
                Some(acrs) => FileLocationStrategy::FromAutocxxRs(PathBuf::from(acrs)),
            },
        }
    }

    pub fn new_custom(gen_dir: PathBuf) -> Self {
        FileLocationStrategy::Custom(gen_dir)
    }

    /// Make a macro to include a given generated Rust file name.
    /// This can't simply be calculated from `get_rs_dir` because
    /// of limitations in rust-analyzer.
    pub fn make_include(&self, fname: String) -> TokenStream {
        match self {
            FileLocationStrategy::FromAutocxxRs(custom_dir) => {
                let fname = custom_dir.join(fname).to_str().unwrap().to_string();
                quote! {
                    include!( #fname );
                }
            }
            FileLocationStrategy::Custom(_) => panic!("Should never happen in the macro"),
            FileLocationStrategy::UnknownMaybeFromOutdir | FileLocationStrategy::FromOutDir(_) => {
                let fname = format!("/{}/{}/{}", BUILD_DIR_NAME, RS_DIR_NAME, fname);
                // rust-analyzer works better if we ask Rust to do the path
                // concatenation rather than doing it in proc-macro code.
                // proc-macro code does not itself have access to the value of
                // OUT_DIR, but if we put it into a macro like the below,
                // rust-analyzer can cope.
                quote! {
                    include!(concat!(env!("OUT_DIR"), #fname));
                }
            }
            FileLocationStrategy::FromAutocxxRsFile(fname) => {
                let fname = fname
                    .to_str()
                    .expect("AUTOCXX_RS_FILE environment variable contained non-UTF8 characters");
                quote! {
                    include!( #fname )
                }
            }
        }
    }

    fn get_gen_dir(&self, suffix: &str) -> PathBuf {
        let root = match self {
            FileLocationStrategy::Custom(gen_dir)
            | FileLocationStrategy::FromAutocxxRs(gen_dir) => gen_dir.clone(),
            FileLocationStrategy::FromOutDir(out_dir) => out_dir.join(BUILD_DIR_NAME),
            FileLocationStrategy::UnknownMaybeFromOutdir => {
                panic!("Could not determine OUT_DIR or AUTOCXX_RS dir")
            }
            FileLocationStrategy::FromAutocxxRsFile(_) => {
                panic!("It's invalid to set AUTOCXX_RS_FILE during the codegen phase.")
            }
        };
        root.join(suffix)
    }

    /// Location to generate Rust files.
    pub fn get_rs_dir(&self) -> PathBuf {
        self.get_gen_dir(RS_DIR_NAME)
    }

    /// Location to generate C++ header files.
    pub fn get_include_dir(&self) -> PathBuf {
        self.get_gen_dir("include")
    }

    /// Location to generate C++ code.
    pub fn get_cxx_dir(&self) -> PathBuf {
        self.get_gen_dir("cxx")
    }

    /// From a build script, inform cargo how to set environment variables
    /// to make them available to the procedural macro.
    pub fn set_cargo_env_vars_for_build(&self) {
        if let FileLocationStrategy::Custom(_) = self {
            println!(
                "cargo:rustc-env={}={}",
                AUTOCXX_RS,
                self.get_rs_dir().to_str().unwrap()
            );
        }
    }
}

impl Default for FileLocationStrategy {
    fn default() -> Self {
        Self::new()
    }
}
<commit_msg>Add missing semicolon.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use proc_macro2::TokenStream;
use quote::quote;
use std::path::PathBuf;

/// The strategy used to generate, and to find generated, files.
/// As standard, these are based off the OUT_DIR set by Cargo,
/// but our code can't assume it can read OUT_DIR as it may
/// be running in the rust-analyzer proc macro server where it's
/// not available. We need to give provision for custom locations
/// and we need our code generator build script to be able to pass
/// locations through to the proc macro by env vars.
///
/// On the whole this class concerns itself with directory names
/// and allows the actual file name to be determined elsewhere
/// (based on a hash of the contents of `include_cpp!`.) But
/// some types of build system need to know the precise file _name_
/// produced by the codegen phase and passed into the macro phase,
/// so we have a `AUTOCXX_RS_FILE` option for that.
pub enum FileLocationStrategy {
    Custom(PathBuf),
    FromAutocxxRsFile(PathBuf),
    FromAutocxxRs(PathBuf),
    FromOutDir(PathBuf),
    UnknownMaybeFromOutdir,
}

static BUILD_DIR_NAME: &str = "autocxx-build-dir";
static RS_DIR_NAME: &str = "rs";
static AUTOCXX_RS: &str = "AUTOCXX_RS";
static AUTOCXX_RS_FILE: &str = "AUTOCXX_RS_FILE";

impl FileLocationStrategy {
    pub fn new() -> Self {
        match std::env::var_os(AUTOCXX_RS_FILE) {
            Some(of) => FileLocationStrategy::FromAutocxxRsFile(PathBuf::from(of)),
            None => match std::env::var_os(AUTOCXX_RS) {
                None => match std::env::var_os("OUT_DIR") {
                    None => FileLocationStrategy::UnknownMaybeFromOutdir,
                    Some(od) => FileLocationStrategy::FromOutDir(PathBuf::from(od)),
                },
                Some(acrs) => FileLocationStrategy::FromAutocxxRs(PathBuf::from(acrs)),
            },
        }
    }

    pub fn new_custom(gen_dir: PathBuf) -> Self {
        FileLocationStrategy::Custom(gen_dir)
    }

    /// Make a macro to include a given generated Rust file name.
    /// This can't simply be calculated from `get_rs_dir` because
    /// of limitations in rust-analyzer.
    pub fn make_include(&self, fname: String) -> TokenStream {
        match self {
            FileLocationStrategy::FromAutocxxRs(custom_dir) => {
                let fname = custom_dir.join(fname).to_str().unwrap().to_string();
                quote! {
                    include!( #fname );
                }
            }
            FileLocationStrategy::Custom(_) => panic!("Should never happen in the macro"),
            FileLocationStrategy::UnknownMaybeFromOutdir | FileLocationStrategy::FromOutDir(_) => {
                let fname = format!("/{}/{}/{}", BUILD_DIR_NAME, RS_DIR_NAME, fname);
                // rust-analyzer works better if we ask Rust to do the path
                // concatenation rather than doing it in proc-macro code.
                // proc-macro code does not itself have access to the value of
                // OUT_DIR, but if we put it into a macro like the below,
                // rust-analyzer can cope.
                quote! {
                    include!(concat!(env!("OUT_DIR"), #fname));
                }
            }
            FileLocationStrategy::FromAutocxxRsFile(fname) => {
                let fname = fname
                    .to_str()
                    .expect("AUTOCXX_RS_FILE environment variable contained non-UTF8 characters");
                quote! {
                    include!( #fname );
                }
            }
        }
    }

    fn get_gen_dir(&self, suffix: &str) -> PathBuf {
        let root = match self {
            FileLocationStrategy::Custom(gen_dir)
            | FileLocationStrategy::FromAutocxxRs(gen_dir) => gen_dir.clone(),
            FileLocationStrategy::FromOutDir(out_dir) => out_dir.join(BUILD_DIR_NAME),
            FileLocationStrategy::UnknownMaybeFromOutdir => {
                panic!("Could not determine OUT_DIR or AUTOCXX_RS dir")
            }
            FileLocationStrategy::FromAutocxxRsFile(_) => {
                panic!("It's invalid to set AUTOCXX_RS_FILE during the codegen phase.")
            }
        };
        root.join(suffix)
    }

    /// Location to generate Rust files.
    pub fn get_rs_dir(&self) -> PathBuf {
        self.get_gen_dir(RS_DIR_NAME)
    }

    /// Location to generate C++ header files.
    pub fn get_include_dir(&self) -> PathBuf {
        self.get_gen_dir("include")
    }

    /// Location to generate C++ code.
    pub fn get_cxx_dir(&self) -> PathBuf {
        self.get_gen_dir("cxx")
    }

    /// From a build script, inform cargo how to set environment variables
    /// to make them available to the procedural macro.
    pub fn set_cargo_env_vars_for_build(&self) {
        if let FileLocationStrategy::Custom(_) = self {
            println!(
                "cargo:rustc-env={}={}",
                AUTOCXX_RS,
                self.get_rs_dir().to_str().unwrap()
            );
        }
    }
}

impl Default for FileLocationStrategy {
    fn default() -> Self {
        Self::new()
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::collections::HashMap;

use parser::ast::{Function, Expr, Statement};
use math::rich_number::{Unit, RichNumber};

use eval::eval_tree_node::EvalTreeNode;
use eval::built_in_function::BuiltInFunction;

use prelude::setup_prelude;

const LOWEST_PRECEDENCE: u8 = 0;
const HIGHEST_PRECEDENCE: u8 = 9;
const FUNCTION_PRECEDENCE: u8 = HIGHEST_PRECEDENCE;

const FUNCTION_FIXITY: Fixity = Fixity::Prefix;

#[derive(PartialEq, Debug)]
pub enum EvalError {
    UndefinedSymbol(String),
    UnexpectedSymbols,
    ExpectedParams(usize),
    InvalidSymbolDefinition {
        expected_params: usize,
        actual_params: usize,
    },
}

pub type EvalResult = Result<ContextItem, EvalError>;

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum Fixity {
    Prefix,
    Infix,
    Postfix,
}

#[derive(PartialEq, Debug, Clone)]
pub enum ContextItem {
    Number(RichNumber),
    Definition {
        // number from 0 to 9 where 9 is the highest precedence
        precedence: u8,
        fixity: Fixity,
        function: Function,
    },
    BuiltInMethod {
        precedence: u8,
        fixity: Fixity,
        params: usize,
        function: BuiltInFunction,
    },
    Unit(Unit),
    Constant(String),
    Boolean(bool),
    Nothing,
}

impl ContextItem {
    /// Creates a Definition ContextItem from a function
    /// with the defaults assumed for all functions
    pub fn function_defaults(function: Function) -> ContextItem {
        ContextItem::Definition {
            precedence: FUNCTION_PRECEDENCE,
            fixity: FUNCTION_FIXITY,
            function: function,
        }
    }

    /// Creates a BuiltInMethod ContextItem from a function
    /// with the defaults assumed for all functions
    pub fn built_in_defaults(function: BuiltInFunction, params: usize) -> ContextItem {
        ContextItem::BuiltInMethod {
            precedence: FUNCTION_PRECEDENCE,
            fixity: FUNCTION_FIXITY,
            params: params,
            function: function,
        }
    }

    pub fn unwrap_number(self) -> RichNumber {
        match self {
            ContextItem::Number(num) => num,
            _ => panic!("Expected to unwrap a Number"),
        }
    }

    pub fn unwrap_boolean(self) -> bool {
        match self {
            ContextItem::Boolean(value) => value,
            _ => panic!("Expected to unwrap a Boolean"),
        }
    }

    /// The most reliable way to get the precedence of any ContextItem
    /// ContextItems with no defined precedence return None
    pub fn resolve_precedence(&self) -> Option<&u8> {
        match *self {
            ContextItem::Definition { ref precedence, .. } => Some(precedence),
            ContextItem::BuiltInMethod { ref precedence, .. } => Some(precedence),
            _ => None,
        }
    }

    /// The most reliable way to get the fixity of any ContextItem
    /// ContextItems with no defined fixity return None
    pub fn resolve_fixity(&self) -> Option<Fixity> {
        match *self {
            ContextItem::Definition { fixity, .. } => Some(fixity),
            ContextItem::BuiltInMethod { fixity, .. } => Some(fixity),
            _ => None,
        }
    }

    /// The most reliable way to get the number of parameters of any ContextItem
    /// ContextItems with no defined number of parameters return None
    pub fn resolve_params(&self) -> Option<usize> {
        match *self {
            ContextItem::Definition {
                function: Function {
                    ref params,
                    ..
                },
                ..
            } => Some(params.len()),
            ContextItem::BuiltInMethod { ref params, .. } => Some(*params),
            _ => None,
        }
    }
}

// (from unit, to unit) : Function definition
pub type ConversionTable = HashMap<(Unit, Unit), Function>;

pub struct EvalContext {
    symbol_table: HashMap<String, ContextItem>,
    conversion_table: ConversionTable,
}

impl EvalContext {
    pub fn new() -> EvalContext {
        EvalContext {
            symbol_table: HashMap::new(),
            conversion_table: HashMap::new(),
        }
    }

    /// Defines a reasonble set of default builtin methods
    pub fn defaults() -> EvalContext {
        let mut context = EvalContext::new();

        context.define_builtin_method(
            "operator",
            FUNCTION_FIXITY,
            FUNCTION_PRECEDENCE,
            4,
            BuiltInFunction::new(defaults::define_operator),
        );

        context
    }

    /// Defines a context with all the defaults as well as definitions
    /// for common operators and units
    pub fn prelude() -> EvalContext {
        let mut context = EvalContext::defaults();
        setup_prelude(&mut context);
        context
    }

    /// Gets a single value without evaluating it from the current context
    pub fn get(&self, name: &str) -> Option<ContextItem> {
        self.symbol_table.get(name).map(|item| (*item).clone())
    }

    /// Convenience method for setting a number in the context
    pub fn set_number(&mut self, name: &str, value: RichNumber) {
        self.set(name, ContextItem::Number(value))
    }

    /// Defines a function in the context
    pub fn define(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        function: Function,
    ) {
        debug_assert!(precedence >= LOWEST_PRECEDENCE && precedence <= HIGHEST_PRECEDENCE);

        self.set(name, ContextItem::Definition {
            fixity: fixity,
            precedence: precedence,
            function: function,
        });
    }

    /// Defines a function linked to actual code rather than an expression
    pub fn define_builtin_method(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        params: usize,
        function: BuiltInFunction,
    ) {

        self.set(name, ContextItem::BuiltInMethod {
            fixity: fixity,
            precedence: precedence,
            params: params,
            function: function,
        });
    }

    /// Creates a constant value
    pub fn set_constant(&mut self, name: &str, value: String) {
        self.set(name, ContextItem::Constant(value));
    }

    /// Creates a boolean value
    pub fn set_boolean(&mut self, name: &str, value: bool) {
        self.set(name, ContextItem::Boolean(value));
    }

    /// Adds to the current context (silently replaces if already present)
    pub fn set(&mut self, name: &str, value: ContextItem) {
        self.symbol_table.insert(name.to_owned(), value);
    }

    pub fn apply(&mut self, statement: Statement) -> EvalResult {
        match statement {
            Statement::NamedFunction {name, definition} => {
                self.define(&name, FUNCTION_FIXITY, FUNCTION_PRECEDENCE, definition);
                Ok(ContextItem::Nothing)
            },
            Statement::AnonymousFunction(_) => Ok(ContextItem::Nothing),
            Statement::Assignment {name, value} => {
                let value = try!(self.evaluate(value));
                self.set(&name, value);
                Ok(ContextItem::Nothing)
            },
            Statement::Expression(value) => self.evaluate(value),
        }
    }

    fn evaluate(&mut self, expr: Expr) -> EvalResult {
        let root = try!(EvalTreeNode::from_expr(self, expr));

        println!("{:#?}", root);

        unimplemented!();
    }
}

mod defaults {
    use std::rc::Rc;

    use super::{EvalContext, ContextItem, EvalResult};
    use eval::built_in_function::BuiltInFunction;

    pub fn define_operator(context: &mut EvalContext, args: Vec<ContextItem>) -> EvalResult {
        Ok(ContextItem::Nothing)
    }
}

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

    use ast::*;
    use math::rich_number::RichNumber;

    #[test]
    fn get_set_in_context() {
        let mut context = EvalContext::new();
        assert_eq!(context.get("a"), None);

        let value = RichNumber::from(2f64);
        context.set_number("a", value.clone());
        assert_eq!(context.get("a").map(|n| n.unwrap_number()), Some(value));
    }

    #[test]
    fn define_variable() {
        let mut context = EvalContext::new();
        apply_string(&mut context, "x = 3");

        assert_eq!(context.get("x").map(|n| n.unwrap_number()), Some(RichNumber::from(3f64)));
    }

    #[test]
    fn basic_operators_and_precedence() {
        let result = apply_single("2 * 3 ** 2 - (100e-1 + -77.2) / 13").unwrap();
        assert_eq!(result.unwrap_number(), RichNumber::from(23.1692307692f64));
    }

    fn test_single_boolean(string: &str, expected: bool) {
        let result = apply_single(string).unwrap();
        assert_eq!(result.unwrap_boolean(), expected);
    }

    fn apply_single(string: &str) -> EvalResult {
        let mut context = EvalContext::new();
        let statement = parse_statement(string);

        context.apply(statement)
    }

    fn parse_statement(string: &str) -> Statement {
        let mut parsed = parse(string).unwrap();
        assert!(parsed.len() == 1, "parse_statement() was passed more than one statement");

        parsed.pop().unwrap()
    }

    fn apply_string(mut context: &mut EvalContext, string: &str) {
        apply_program(context, parse(string).unwrap());
    }

    fn apply_program(mut context: &mut EvalContext, program: Program) {
        for statement in program {
            context.apply(statement).expect("Error while applying statement");
        }
    }
}

<commit_msg>Defining fixity constants and starting to implement define_operator<commit_after>use std::rc::Rc;
use std::collections::HashMap;

use parser::ast::{Function, Expr, Statement};
use math::rich_number::{Unit, RichNumber};

use eval::eval_tree_node::EvalTreeNode;
use eval::built_in_function::BuiltInFunction;

use prelude::setup_prelude;

const LOWEST_PRECEDENCE: u8 = 0;
const HIGHEST_PRECEDENCE: u8 = 9;
const FUNCTION_PRECEDENCE: u8 = HIGHEST_PRECEDENCE;

const FUNCTION_FIXITY: Fixity = Fixity::Prefix;

#[derive(PartialEq, Debug)]
pub enum EvalError {
    UndefinedSymbol(String),
    UnexpectedSymbols,
    ExpectedParams(usize),
    InvalidSymbolDefinition {
        expected_params: usize,
        actual_params: usize,
    },
}

pub type EvalResult = Result<ContextItem, EvalError>;

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum Fixity {
    Prefix,
    Infix,
    Postfix,
}

//TODO: Move Fixity into its own module and replace these string literals with `const` declarations
impl Fixity {
    fn from_string(string: String) -> Option<Self> {
        Some(match string.as_ref() {
            "PREFIX" => Fixity::Prefix,
            "INFIX" => Fixity::Infix,
            "POSTFIX" => Fixity::Postfix,
            _ => return None,
        })
    }
}

impl ToString for Fixity {
    fn to_string(&self) -> String {
        String::from(match *self {
            Fixity::Prefix => "PREFIX",
            Fixity::Infix => "INFIX",
            Fixity::Postfix => "POSTFIX",
        })
    }
}

#[derive(PartialEq, Debug, Clone)]
pub enum ContextItem {
    Number(RichNumber),
    Definition {
        // number from 0 to 9 where 9 is the highest precedence
        precedence: u8,
        fixity: Fixity,
        function: Function,
    },
    BuiltInMethod {
        precedence: u8,
        fixity: Fixity,
        params: usize,
        function: BuiltInFunction,
    },
    Unit(Unit),
    Constant(String),
    Boolean(bool),
    Nothing,
}

impl ContextItem {
    /// Creates a Definition ContextItem from a function
    /// with the defaults assumed for all functions
    pub fn function_defaults(function: Function) -> ContextItem {
        ContextItem::Definition {
            precedence: FUNCTION_PRECEDENCE,
            fixity: FUNCTION_FIXITY,
            function: function,
        }
    }

    /// Creates a BuiltInMethod ContextItem from a function
    /// with the defaults assumed for all functions
    pub fn built_in_defaults(function: BuiltInFunction, params: usize) -> ContextItem {
        ContextItem::BuiltInMethod {
            precedence: FUNCTION_PRECEDENCE,
            fixity: FUNCTION_FIXITY,
            params: params,
            function: function,
        }
    }

    pub fn unwrap_number(self) -> RichNumber {
        match self {
            ContextItem::Number(num) => num,
            _ => panic!("Expected to unwrap a Number"),
        }
    }

    pub fn unwrap_boolean(self) -> bool {
        match self {
            ContextItem::Boolean(value) => value,
            _ => panic!("Expected to unwrap a Boolean"),
        }
    }

    /// The most reliable way to get the precedence of any ContextItem
    /// ContextItems with no defined precedence return None
    pub fn resolve_precedence(&self) -> Option<&u8> {
        match *self {
            ContextItem::Definition { ref precedence, .. } => Some(precedence),
            ContextItem::BuiltInMethod { ref precedence, .. } => Some(precedence),
            _ => None,
        }
    }

    /// The most reliable way to get the fixity of any ContextItem
    /// ContextItems with no defined fixity return None
    pub fn resolve_fixity(&self) -> Option<Fixity> {
        match *self {
            ContextItem::Definition { fixity, .. } => Some(fixity),
            ContextItem::BuiltInMethod { fixity, .. } => Some(fixity),
            _ => None,
        }
    }

    /// The most reliable way to get the number of parameters of any ContextItem
    /// ContextItems with no defined number of parameters return None
    pub fn resolve_params(&self) -> Option<usize> {
        match *self {
            ContextItem::Definition {
                function: Function {
                    ref params,
                    ..
                },
                ..
            } => Some(params.len()),
            ContextItem::BuiltInMethod { ref params, .. } => Some(*params),
            _ => None,
        }
    }
}

// (from unit, to unit) : Function definition
pub type ConversionTable = HashMap<(Unit, Unit), Function>;

pub struct EvalContext {
    symbol_table: HashMap<String, ContextItem>,
    conversion_table: ConversionTable,
}

impl EvalContext {
    pub fn new() -> EvalContext {
        EvalContext {
            symbol_table: HashMap::new(),
            conversion_table: HashMap::new(),
        }
    }

    /// Defines a reasonble set of default builtin methods
    pub fn defaults() -> EvalContext {
        let mut context = EvalContext::new();

        context.set_constant("PREFIX", Fixity::Prefix.to_string());
        context.set_constant("INFIX", Fixity::Infix.to_string());
        context.set_constant("POSTFIX", Fixity::Postfix.to_string());

        context.define_builtin_method(
            "operator",
            FUNCTION_FIXITY,
            FUNCTION_PRECEDENCE,
            4,
            BuiltInFunction::new(defaults::define_operator),
        );

        context
    }

    /// Defines a context with all the defaults as well as definitions
    /// for common operators and units
    pub fn prelude() -> EvalContext {
        let mut context = EvalContext::defaults();
        setup_prelude(&mut context);
        context
    }

    /// Gets a single value without evaluating it from the current context
    pub fn get(&self, name: &str) -> Option<ContextItem> {
        self.symbol_table.get(name).map(|item| (*item).clone())
    }

    /// Convenience method for setting a number in the context
    pub fn set_number(&mut self, name: &str, value: RichNumber) {
        self.set(name, ContextItem::Number(value))
    }

    /// Defines a function in the context
    pub fn define(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        function: Function,
    ) {
        debug_assert!(precedence >= LOWEST_PRECEDENCE && precedence <= HIGHEST_PRECEDENCE);

        self.set(name, ContextItem::Definition {
            fixity: fixity,
            precedence: precedence,
            function: function,
        });
    }

    /// Defines a function linked to actual code rather than an expression
    pub fn define_builtin_method(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        params: usize,
        function: BuiltInFunction,
    ) {

        self.set(name, ContextItem::BuiltInMethod {
            fixity: fixity,
            precedence: precedence,
            params: params,
            function: function,
        });
    }

    /// Creates a constant value
    pub fn set_constant(&mut self, name: &str, value: String) {
        self.set(name, ContextItem::Constant(value));
    }

    /// Creates a boolean value
    pub fn set_boolean(&mut self, name: &str, value: bool) {
        self.set(name, ContextItem::Boolean(value));
    }

    /// Adds to the current context (silently replaces if already present)
    pub fn set(&mut self, name: &str, value: ContextItem) {
        self.symbol_table.insert(name.to_owned(), value);
    }

    pub fn apply(&mut self, statement: Statement) -> EvalResult {
        match statement {
            Statement::NamedFunction {name, definition} => {
                self.define(&name, FUNCTION_FIXITY, FUNCTION_PRECEDENCE, definition);
                Ok(ContextItem::Nothing)
            },
            Statement::AnonymousFunction(_) => Ok(ContextItem::Nothing),
            Statement::Assignment {name, value} => {
                let value = try!(self.evaluate(value));
                self.set(&name, value);
                Ok(ContextItem::Nothing)
            },
            Statement::Expression(value) => self.evaluate(value),
        }
    }

    fn evaluate(&mut self, expr: Expr) -> EvalResult {
        let root = try!(EvalTreeNode::from_expr(self, expr));

        println!("{:#?}", root);

        unimplemented!();
    }
}

mod defaults {
    use std::rc::Rc;

    use super::{EvalContext, ContextItem, EvalResult, EvalError};
    use eval::built_in_function::BuiltInFunction;

    pub fn define_operator(context: &mut EvalContext, args: Vec<ContextItem>) -> EvalResult {
        try!(expect_args(&args, 4));

        //TODO: Unpack each argument form its context item and Err if it isn't the expected type

        Ok(ContextItem::Nothing)
    }

    fn expect_args(args: &Vec<ContextItem>, nargs: usize) -> Result<(), EvalError> {
        if args.len() != nargs {
            Err(EvalError::ExpectedParams(nargs))
        }
        else {
            Ok(())
        }
    }
}

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

    use ast::*;
    use math::rich_number::RichNumber;

    #[test]
    fn get_set_in_context() {
        let mut context = EvalContext::new();
        assert_eq!(context.get("a"), None);

        let value = RichNumber::from(2f64);
        context.set_number("a", value.clone());
        assert_eq!(context.get("a").map(|n| n.unwrap_number()), Some(value));
    }

    #[test]
    fn define_variable() {
        let mut context = EvalContext::new();
        apply_string(&mut context, "x = 3");

        assert_eq!(context.get("x").map(|n| n.unwrap_number()), Some(RichNumber::from(3f64)));
    }

    #[test]
    fn basic_operators_and_precedence() {
        let result = apply_single("2 * 3 ** 2 - (100e-1 + -77.2) / 13").unwrap();
        assert_eq!(result.unwrap_number(), RichNumber::from(23.1692307692f64));
    }

    fn test_single_boolean(string: &str, expected: bool) {
        let result = apply_single(string).unwrap();
        assert_eq!(result.unwrap_boolean(), expected);
    }

    fn apply_single(string: &str) -> EvalResult {
        let mut context = EvalContext::new();
        let statement = parse_statement(string);

        context.apply(statement)
    }

    fn parse_statement(string: &str) -> Statement {
        let mut parsed = parse(string).unwrap();
        assert!(parsed.len() == 1, "parse_statement() was passed more than one statement");

        parsed.pop().unwrap()
    }

    fn apply_string(mut context: &mut EvalContext, string: &str) {
        apply_program(context, parse(string).unwrap());
    }

    fn apply_program(mut context: &mut EvalContext, program: Program) {
        for statement in program {
            context.apply(statement).expect("Error while applying statement");
        }
    }
}

<|endoftext|>


<commit_before>use std::mem;

use rand::os::OsRng;
use rand::XorShiftRng;
use rand::Rand;
use rand::Rng;
use rand::SeedableRng;

use rayon::prelude::*;
use smallvec::SmallVec;

use tile::Faction;

use util::{Error, Direction};

use level::{Level, add_isize_to_usize};

pub struct FactionGen {
    rand: XorShiftRng,
}

impl FactionGen {
    pub fn new() -> FactionGen {
        FactionGen {
            rand: XorShiftRng::rand(&mut OsRng::new().unwrap()),
        }
    }
    #[inline]
    pub fn generate(&mut self, level: &mut Level<Faction>, buffer: &mut Level<Faction>) {
        let mut lovel = SuperUnsafe(buffer as *mut Level<Faction>);
        let width = level.get_width();
        let height = level.get_height();
        let number = self.rand.next_u32();
        let level_ref = &*level;
        (0..width).into_par_iter()
            .map(|x| (x, (0..height).into_par_iter()))
            .flat_map(|(x, ys)| {
                ys.flat_map(move |y| {
                    let x_seed = (x as u64 ^ (x as u64 >> 32)) as u32;
                    let y_seed = (y as u64 ^ (y as u64 >> 32)) as u32;
                    let mut rand = XorShiftRng::from_seed([number, x_seed, y_seed, 1]);
                    rand.next_u32();
                    rand.next_u32();
                    let mut deck = SmallVec::<[_; 9]>::new();
                    match level_ref.get_tile(x, y) {
                        Ok(tile) => {
                            match *tile {
                                Faction::Faction(_) => {
                                    deck.push(tile.clone());
                                },
                                Faction::Void => return None,
                                _ => {},
                            }
                        },
                        Err(Error::IndexOutOfBounds) => {
                            unreachable!("Generate method indexed out of bounds while simulating a step. This should never happen unless the programmer is not very bright.");
                        }
                    }
                    Self::get_faction_neighbours(x, y, &mut deck, level_ref);
                    rand.choose(&deck)
                        .map(|f| ((x, y), f.clone()))
                })
            })
            .for_each(|((x, y), f)| {
                //this should be safe, right?
                if let Ok(tile) = unsafe{ &mut *lovel.0 }.get_mut_tile(x, y) {
                    *tile = f;
                }
            });
        mem::swap(level, buffer);
    }

    fn get_faction_neighbours(x: usize, y: usize, deck: &mut SmallVec<[Faction;9]>, level: &Level<Faction>) {
        for d in Direction::get_dirs() {
            let (ix, iy) = d.get_tuple();
            let coord = match (add_isize_to_usize(ix, x), add_isize_to_usize(iy, y)) {
                (Some(x), Some(y)) => (x,y),
                _ => continue,
            };
            match level.get_tile_with_tuple(coord) {
                Ok(f @ &Faction::Faction(_)) => deck.push(f.clone()),
                _ => {},
            }
        }
    }
}
//this struct is unsafe. Use it with great caution.
struct SuperUnsafe(*mut Level<Faction>);
unsafe impl Sync for SuperUnsafe{}
<commit_msg>whoops. forgot something<commit_after>use std::mem;

use rand::os::OsRng;
use rand::XorShiftRng;
use rand::Rand;
use rand::Rng;
use rand::SeedableRng;

use rayon::prelude::*;
use smallvec::SmallVec;

use tile::Faction;

use util::{Error, Direction};

use level::{Level, add_isize_to_usize};

pub struct FactionGen {
    rand: XorShiftRng,
}

impl FactionGen {
    pub fn new() -> FactionGen {
        FactionGen {
            rand: XorShiftRng::rand(&mut OsRng::new().unwrap()),
        }
    }
    #[inline]
    pub fn generate(&mut self, level: &mut Level<Faction>, buffer: &mut Level<Faction>) {
        let mut lovel = SuperUnsafe(buffer as *mut Level<Faction>);
        let width = level.get_width();
        let height = level.get_height();
        let number = self.rand.next_u32();
        {
            let level_ref = &*level;
            (0..width).into_par_iter()
                .map(|x| (x, (0..height).into_par_iter()))
                .flat_map(|(x, ys)| {
                    ys.flat_map(move |y| {
                        let x_seed = (x as u64 ^ (x as u64 >> 32)) as u32;
                        let y_seed = (y as u64 ^ (y as u64 >> 32)) as u32;
                        let mut rand = XorShiftRng::from_seed([number, x_seed, y_seed, 1]);
                        rand.next_u32();
                        rand.next_u32();
                        let mut deck = SmallVec::<[_; 9]>::new();
                        match level_ref.get_tile(x, y) {
                            Ok(tile) => {
                                match *tile {
                                    Faction::Faction(_) => {
                                        deck.push(tile.clone());
                                    },
                                    Faction::Void => return None,
                                    _ => {},
                                }
                            },
                            Err(Error::IndexOutOfBounds) => {
                                unreachable!("Generate method indexed out of bounds while simulating a step. This should never happen unless the programmer is not very bright.");
                            }
                        }
                        Self::get_faction_neighbours(x, y, &mut deck, level_ref);
                        rand.choose(&deck)
                            .map(|f| ((x, y), f.clone()))
                    })
                })
                .for_each(|((x, y), f)| {
                    //this should be safe, right?
                    if let Ok(tile) = unsafe{ &mut *lovel.0 }.get_mut_tile(x, y) {
                        *tile = f;
                    }
                });
        }
        mem::swap(level, buffer);
    }

    fn get_faction_neighbours(x: usize, y: usize, deck: &mut SmallVec<[Faction;9]>, level: &Level<Faction>) {
        for d in Direction::get_dirs() {
            let (ix, iy) = d.get_tuple();
            let coord = match (add_isize_to_usize(ix, x), add_isize_to_usize(iy, y)) {
                (Some(x), Some(y)) => (x,y),
                _ => continue,
            };
            match level.get_tile_with_tuple(coord) {
                Ok(f @ &Faction::Faction(_)) => deck.push(f.clone()),
                _ => {},
            }
        }
    }
}
//this struct is unsafe. Use it with great caution.
struct SuperUnsafe(*mut Level<Faction>);
unsafe impl Sync for SuperUnsafe{}
<|endoftext|>


<commit_before>use traits::Coord;

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct GridCoord {
    x: i32,
    y: i32,
}

impl GridCoord {

    #[inline]
    pub fn from_offset(offset: i32, rows: i32, cols: i32) -> GridCoord {
        let col = offset % cols;
        let row = (offset - col) / rows;

        GridCoord {
            x: col,
            y: row,
        }
    }
}

impl Coord for GridCoord {

    fn from_2d(x: i32, y: i32) -> Self {
        GridCoord {
            x: x,
            y: y,
        }
    }

    fn x(&self) -> i32 { self.x }

    fn y(&self) -> i32 { self.y }
}

#[cfg(test)]
mod tests {

    use traits::Coord;
    use traits::Nhood;
    use grid::nhood::MooreNhood;
    use super::GridCoord;

    #[test]
    fn test_from_offset() {
        let c = GridCoord::from_offset(0, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 0);

        let c = GridCoord::from_offset(10, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 1);

        let c = GridCoord::from_offset(100, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 10);
    }

    #[test]
    fn test_with_moore_nhood() {
        // 3 x 3 square grid with Moore's neighborhood

        let nhood = MooreNhood::new();

        let center = GridCoord::from_2d(1, 1);

        let neighbors = nhood.neighbors(&center);
        assert_eq!(neighbors.len(), nhood.neighbors_count());

        assert_eq!(neighbors[0], GridCoord::from_2d(0, 0));
        assert_eq!(neighbors[1], GridCoord::from_2d(1, 0));
        assert_eq!(neighbors[2], GridCoord::from_2d(2, 0));
        assert_eq!(neighbors[3], GridCoord::from_2d(0, 1));
        assert_eq!(neighbors[4], GridCoord::from_2d(2, 1));
        assert_eq!(neighbors[5], GridCoord::from_2d(0, 2));
        assert_eq!(neighbors[6], GridCoord::from_2d(1, 2));
        assert_eq!(neighbors[7], GridCoord::from_2d(2, 2));
    }
}<commit_msg>Fixed from_offset + tests.<commit_after>use traits::Coord;

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct GridCoord {
    x: i32,
    y: i32,
}

impl GridCoord {

    #[inline]
    pub fn from_offset(offset: i32, rows: i32, cols: i32) -> GridCoord {
        let col = offset % cols;
        let row = (offset - col) / cols;

        debug_assert!(row < rows);

        GridCoord {
            x: col,
            y: row,
        }
    }
}

impl Coord for GridCoord {

    fn from_2d(x: i32, y: i32) -> Self {
        GridCoord {
            x: x,
            y: y,
        }
    }

    fn x(&self) -> i32 { self.x }

    fn y(&self) -> i32 { self.y }
}

#[cfg(test)]
mod tests {

    use traits::Coord;
    use traits::Nhood;
    use grid::nhood::MooreNhood;
    use super::GridCoord;

    #[test]
    fn test_from_offset() {
        let c = GridCoord::from_offset(0, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 0);

        let c = GridCoord::from_offset(10, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 1);

        let c = GridCoord::from_offset(99, 10, 10);
        assert_eq!(c.x(), 9);
        assert_eq!(c.y(), 9);

        let c = GridCoord::from_offset(55, 5, 12);
        assert_eq!(c.x(), 7);
        assert_eq!(c.y(), 4);
    }

    #[test]
    #[should_panic]
    fn test_wrong_offset() {
        GridCoord::from_offset(100, 10, 10);
    }

    #[test]
    fn test_with_moore_nhood() {
        // 3 x 3 square grid with Moore's neighborhood

        let nhood = MooreNhood::new();

        let center = GridCoord::from_2d(1, 1);

        let neighbors = nhood.neighbors(&center);
        assert_eq!(neighbors.len(), nhood.neighbors_count());

        assert_eq!(neighbors[0], GridCoord::from_2d(0, 0));
        assert_eq!(neighbors[1], GridCoord::from_2d(1, 0));
        assert_eq!(neighbors[2], GridCoord::from_2d(2, 0));
        assert_eq!(neighbors[3], GridCoord::from_2d(0, 1));
        assert_eq!(neighbors[4], GridCoord::from_2d(2, 1));
        assert_eq!(neighbors[5], GridCoord::from_2d(0, 2));
        assert_eq!(neighbors[6], GridCoord::from_2d(1, 2));
        assert_eq!(neighbors[7], GridCoord::from_2d(2, 2));
    }
}<|endoftext|>


<commit_before>#[macro_use(log)]
extern crate logger;
extern crate rand;
extern crate time;
extern crate util;

use std::collections::HashMap;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Error as IOError;
use std::io::Write;
use std::num::ParseIntError;
use std::path::Path;
use std::str::from_utf8;
use std::str::FromStr;
use std::str::Utf8Error;

use util::splitargs;
use logger::{Logger, Level};

pub struct Config {
    pub logger: Logger,
    pub daemonize: bool,
    pub databases: u8,
    pub pidfile: String,
    pub bind: Vec<String>,
    pub port: u16,
    pub tcp_keepalive: u32,
    pub active_rehashing: bool,
    pub set_max_intset_entries: usize,
    pub timeout: u64,
    pub unixsocket: Option<String>,
    pub unixsocketperm: u32,
    pub rename_commands: HashMap<String, Option<String>>,
}

#[derive(Debug)]
pub enum ConfigError {
    InvalidFormat,
    InvalidParameter,
    IOError(IOError),
    FileNotFound,
}

fn read_string(args: Vec<Vec<u8>>) -> Result<String, ConfigError> {
    if args.len() != 2 {
        Err(ConfigError::InvalidFormat)
    } else {
        Ok(try!(from_utf8(&*args[1])).to_owned())
    }
}

fn read_parse<T>(args: Vec<Vec<u8>>) -> Result<T, ConfigError>
        where T: FromStr {
    let s = try!(read_string(args));
    match s.parse() {
        Ok(f) => Ok(f),
        Err(_) => Err(ConfigError::InvalidParameter),
    }
}

fn read_bool(args: Vec<Vec<u8>>) -> Result<bool, ConfigError> {
    Ok(match &*try!(read_string(args)) {
        "yes" => true,
        "no" => false,
        _ => return Err(ConfigError::InvalidFormat),
    })
}

impl Config {
    pub fn mock(port: u16, logger: Logger) -> Config {
        Config {
            logger: logger,
            active_rehashing: true,
            daemonize: false,
            databases: 16,
            pidfile: "/var/run/sredis.pid".to_owned(),
            bind: vec!["127.0.0.1".to_owned()],
            port: port,
            tcp_keepalive: 0,
            set_max_intset_entries: 512,
            timeout: 0,
            unixsocket: None,
            unixsocketperm: 0700,
            rename_commands: HashMap::new(),
        }
    }

    pub fn new(logger: Logger) -> Config {
        Config {
            logger: logger,
            active_rehashing: true,
            daemonize: false,
            databases: 16,
            pidfile: "/var/run/sredis.pid".to_owned(),
            bind: vec![],
            port: 6379,
            tcp_keepalive: 0,
            set_max_intset_entries: 512,
            timeout: 0,
            unixsocket: None,
            unixsocketperm: 0700,
            rename_commands: HashMap::new(),
        }
    }

    pub fn parsefile(&mut self, fname: String) -> Result<(), ConfigError> {
        let path = Path::new(&*fname);
        let file = BufReader::new(match File::open(&path) {
            Ok(f) => f,
            Err(_) => {
                log!(self.logger, Warning, "Fatal error, can't open config file '{}'", fname);
                return Err(ConfigError::FileNotFound);
            }
        });
        for line_iter in file.lines() {
            let lline = try!(line_iter);
            let line = lline.trim();
            if line.starts_with("#") {
                continue;
            }

            let args = match splitargs(line.as_bytes()) {
                Ok(args) => args,
                Err(_) => return Err(ConfigError::InvalidFormat),
            };

            if args.len() == 0 {
                continue;
            }

            match &*args[0] {
                b"bind" => self.bind.extend(args[1..].iter().filter(|x| x.len() > 0).map(|x| match from_utf8(x) {
                            Ok(s) => s.to_owned(),
                            Err(_) => "".to_owned(), // TODO: return ConfigError
                            })),
                b"port" => self.port = try!(read_parse(args)),
                b"activerehashing" => self.active_rehashing = try!(read_bool(args)),
                b"daemonize" => self.daemonize = try!(read_bool(args)),
                b"databases" => self.databases = try!(read_parse(args)),
                b"tcp-keepalive" => self.tcp_keepalive = try!(read_parse(args)),
                b"set-max-intset-entries" => self.set_max_intset_entries = try!(read_parse(args)),
                b"timeout" => self.timeout = try!(read_parse(args)),
                b"unixsocket" => self.unixsocket = Some(try!(read_string(args)).to_owned()),
                b"unixsocketperm" => self.unixsocketperm = try!(u32::from_str_radix(&*try!(read_string(args)), 8)),
                b"pidfile" => self.pidfile = try!(read_string(args)).to_owned(),
                b"logfile" => try!(self.logger.set_logfile(&*try!(read_string(args)))),
                b"loglevel" => self.logger.set_loglevel(match &*try!(read_string(args)) {
                    "debug" => Level::Debug,
                    "verbose" => Level::Verbose,
                    "notice" => Level::Notice,
                    "warning" => Level::Warning,
                    _ => return Err(ConfigError::InvalidParameter),
                }),
                b"rename-command" => {
                    if args.len() != 3 {
                        return Err(ConfigError::InvalidFormat)
                    } else {
                        let command = try!(from_utf8(&*args[1])).to_owned();
                        let newname = try!(from_utf8(&*args[2])).to_owned();
                        if newname.len() > 0 {
                            self.rename_commands.insert(newname, Some(command.clone()));
                        }
                        self.rename_commands.insert(command, None);
                    }
                },
                b"include" => if args.len() != 2 {
                    return Err(ConfigError::InvalidFormat)
                } else {
                    try!(self.parsefile(try!(from_utf8(&*args[1])).to_owned()));
                },
                _ => writeln!(&mut std::io::stderr(), "Unknown configuration {:?}", line).unwrap(),
            };
        }

        Ok(())
    }

    pub fn addresses(&self) -> Vec<(String, u16)> {
        if self.bind.len() == 0 {
            vec![("127.0.0.1".to_owned(), self.port)]
        } else {
            self.bind.iter().map(|s| (s.clone(), self.port)).collect::<Vec<_>>()
        }
    }
}

impl From<IOError> for ConfigError {
    fn from(e: IOError) -> ConfigError { ConfigError::IOError(e) }
}

impl From<ParseIntError> for ConfigError {
    fn from(_: ParseIntError) -> ConfigError { ConfigError::InvalidParameter }
}

impl From<Utf8Error> for ConfigError {
    fn from(_: Utf8Error) -> ConfigError { ConfigError::InvalidParameter }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashMap;
    use std::fs::File;
    use std::fs::create_dir;
    use std::io::Write;

    use rand::random;

    use logger::Logger;
    use util::mstime;

    macro_rules! config {
        ($str: expr, $logger: expr) => ({
            let dirpath = format!("tmp/{}", mstime());
            let filepath = format!("{}/{}.conf", dirpath, random::<u64>());
            match create_dir("tmp") { _ => () }
            match create_dir(dirpath) { _ => () }
            match File::create(filepath.clone()).unwrap().write_all($str) { _ => () }
            let mut config = Config::new($logger);
            config.parsefile(filepath).unwrap();
            config
        })
    }

    #[test]
    fn parse_bind() {
        let config = config!(b"bind 1.2.3.4\nbind 5.6.7.8", Logger::null());
        assert_eq!(config.bind, vec!["1.2.3.4", "5.6.7.8"]);
        assert_eq!(config.port, 6379);
    }

    #[test]
    fn parse_port() {
        let config = config!(b"port 12345", Logger::null());
        assert_eq!(config.port, 12345);
        assert_eq!(config.addresses(), vec![("127.0.0.1".to_owned(), 12345)]);
    }

    #[test]
    fn parse_bind_port() {
        let config = config!(b"bind 127.0.0.1\nport 12345", Logger::null());
        assert_eq!(config.bind, vec!["127.0.0.1"]);
        assert_eq!(config.port, 12345);
    }

    #[test]
    fn parse_daemonize_yes() {
        let config = config!(b"daemonize yes", Logger::null());
        assert!(config.daemonize);
    }

    #[test]
    fn parse_daemonize_no() {
        let config = config!(b"daemonize no", Logger::null());
        assert!(!config.daemonize);
    }

    #[test]
    fn parse_active_rehashing_yes() {
        let config = config!(b"activerehashing yes", Logger::null());
        assert!(config.active_rehashing);
    }

    #[test]
    fn parse_active_rehashing_no() {
        let config = config!(b"activerehashing no", Logger::null());
        assert!(!config.active_rehashing);
    }

    #[test]
    fn parse_databases() {
        let config = config!(b"databases 20", Logger::null());
        assert_eq!(config.databases, 20);
    }

    #[test]
    fn parse_keepalive() {
        let config = config!(b"tcp-keepalive 123", Logger::null());
        assert_eq!(config.tcp_keepalive, 123);
    }

    #[test]
    fn parse_keepalive_quotes() {
        let config = config!(b"tcp-keepalive \"123\"", Logger::null());
        assert_eq!(config.tcp_keepalive, 123);
    }

    #[test]
    fn parse_set_max_intset_entries() {
        let config = config!(b"set-max-intset-entries 123456", Logger::null());
        assert_eq!(config.set_max_intset_entries, 123456);
    }

    #[test]
    fn parse_timeout() {
        let config = config!(b"timeout 23456", Logger::null());
        assert_eq!(config.timeout, 23456);
    }

    #[test]
    fn parse_unixsocket() {
        let config = config!(b"unixsocket /dev/null\nunixsocketperm 777", Logger::null());
        assert_eq!(config.unixsocket, Some("/dev/null".to_owned()));
        assert_eq!(config.unixsocketperm, 511);
    }

    #[test]
    fn parse_rename_commands() {
        let config = config!(b"rename-command c1 c2\nrename-command hello world", Logger::null());
        let mut h = HashMap::new();
        h.insert("c2".to_owned(), Some("c1".to_owned()));
        h.insert("c1".to_owned(), None);
        h.insert("world".to_owned(), Some("hello".to_owned()));
        h.insert("hello".to_owned(), None);
        assert_eq!(config.rename_commands, h);
    }
}
<commit_msg>Make rename case insensitive<commit_after>#![feature(owned_ascii_ext)]

#[macro_use(log)]
extern crate logger;
extern crate rand;
extern crate time;
extern crate util;

use std::ascii::OwnedAsciiExt;
use std::collections::HashMap;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Error as IOError;
use std::io::Write;
use std::num::ParseIntError;
use std::path::Path;
use std::str::from_utf8;
use std::str::FromStr;
use std::str::Utf8Error;

use util::splitargs;
use logger::{Logger, Level};

pub struct Config {
    pub logger: Logger,
    pub daemonize: bool,
    pub databases: u8,
    pub pidfile: String,
    pub bind: Vec<String>,
    pub port: u16,
    pub tcp_keepalive: u32,
    pub active_rehashing: bool,
    pub set_max_intset_entries: usize,
    pub timeout: u64,
    pub unixsocket: Option<String>,
    pub unixsocketperm: u32,
    pub rename_commands: HashMap<String, Option<String>>,
}

#[derive(Debug)]
pub enum ConfigError {
    InvalidFormat,
    InvalidParameter,
    IOError(IOError),
    FileNotFound,
}

fn read_string(args: Vec<Vec<u8>>) -> Result<String, ConfigError> {
    if args.len() != 2 {
        Err(ConfigError::InvalidFormat)
    } else {
        Ok(try!(from_utf8(&*args[1])).to_owned())
    }
}

fn read_parse<T>(args: Vec<Vec<u8>>) -> Result<T, ConfigError>
        where T: FromStr {
    let s = try!(read_string(args));
    match s.parse() {
        Ok(f) => Ok(f),
        Err(_) => Err(ConfigError::InvalidParameter),
    }
}

fn read_bool(args: Vec<Vec<u8>>) -> Result<bool, ConfigError> {
    Ok(match &*try!(read_string(args)) {
        "yes" => true,
        "no" => false,
        _ => return Err(ConfigError::InvalidFormat),
    })
}

impl Config {
    pub fn mock(port: u16, logger: Logger) -> Config {
        Config {
            logger: logger,
            active_rehashing: true,
            daemonize: false,
            databases: 16,
            pidfile: "/var/run/sredis.pid".to_owned(),
            bind: vec!["127.0.0.1".to_owned()],
            port: port,
            tcp_keepalive: 0,
            set_max_intset_entries: 512,
            timeout: 0,
            unixsocket: None,
            unixsocketperm: 0700,
            rename_commands: HashMap::new(),
        }
    }

    pub fn new(logger: Logger) -> Config {
        Config {
            logger: logger,
            active_rehashing: true,
            daemonize: false,
            databases: 16,
            pidfile: "/var/run/sredis.pid".to_owned(),
            bind: vec![],
            port: 6379,
            tcp_keepalive: 0,
            set_max_intset_entries: 512,
            timeout: 0,
            unixsocket: None,
            unixsocketperm: 0700,
            rename_commands: HashMap::new(),
        }
    }

    pub fn parsefile(&mut self, fname: String) -> Result<(), ConfigError> {
        let path = Path::new(&*fname);
        let file = BufReader::new(match File::open(&path) {
            Ok(f) => f,
            Err(_) => {
                log!(self.logger, Warning, "Fatal error, can't open config file '{}'", fname);
                return Err(ConfigError::FileNotFound);
            }
        });
        for line_iter in file.lines() {
            let lline = try!(line_iter);
            let line = lline.trim();
            if line.starts_with("#") {
                continue;
            }

            let args = match splitargs(line.as_bytes()) {
                Ok(args) => args,
                Err(_) => return Err(ConfigError::InvalidFormat),
            };

            if args.len() == 0 {
                continue;
            }

            match &*args[0] {
                b"bind" => self.bind.extend(args[1..].iter().filter(|x| x.len() > 0).map(|x| match from_utf8(x) {
                            Ok(s) => s.to_owned(),
                            Err(_) => "".to_owned(), // TODO: return ConfigError
                            })),
                b"port" => self.port = try!(read_parse(args)),
                b"activerehashing" => self.active_rehashing = try!(read_bool(args)),
                b"daemonize" => self.daemonize = try!(read_bool(args)),
                b"databases" => self.databases = try!(read_parse(args)),
                b"tcp-keepalive" => self.tcp_keepalive = try!(read_parse(args)),
                b"set-max-intset-entries" => self.set_max_intset_entries = try!(read_parse(args)),
                b"timeout" => self.timeout = try!(read_parse(args)),
                b"unixsocket" => self.unixsocket = Some(try!(read_string(args)).to_owned()),
                b"unixsocketperm" => self.unixsocketperm = try!(u32::from_str_radix(&*try!(read_string(args)), 8)),
                b"pidfile" => self.pidfile = try!(read_string(args)).to_owned(),
                b"logfile" => {
                    let logfile = try!(read_string(args));
                    if logfile.len() > 0 {
                        try!(self.logger.set_logfile(&*logfile))
                    }
                },
                b"loglevel" => self.logger.set_loglevel(match &*try!(read_string(args)) {
                    "debug" => Level::Debug,
                    "verbose" => Level::Verbose,
                    "notice" => Level::Notice,
                    "warning" => Level::Warning,
                    _ => return Err(ConfigError::InvalidParameter),
                }),
                b"rename-command" => {
                    if args.len() != 3 {
                        return Err(ConfigError::InvalidFormat)
                    } else {
                        let command = try!(from_utf8(&*args[1])).to_owned();
                        let newname = try!(from_utf8(&*args[2])).to_owned();
                        if newname.len() > 0 {
                            self.rename_commands.insert(newname.into_ascii_lowercase(), Some(command.clone().into_ascii_lowercase()));
                        }
                        self.rename_commands.insert(command.into_ascii_lowercase(), None);
                    }
                },
                b"include" => if args.len() != 2 {
                    return Err(ConfigError::InvalidFormat)
                } else {
                    try!(self.parsefile(try!(from_utf8(&*args[1])).to_owned()));
                },
                _ => writeln!(&mut std::io::stderr(), "Unknown configuration {:?}", line).unwrap(),
            };
        }

        Ok(())
    }

    pub fn addresses(&self) -> Vec<(String, u16)> {
        if self.bind.len() == 0 {
            vec![("127.0.0.1".to_owned(), self.port)]
        } else {
            self.bind.iter().map(|s| (s.clone(), self.port)).collect::<Vec<_>>()
        }
    }
}

impl From<IOError> for ConfigError {
    fn from(e: IOError) -> ConfigError { ConfigError::IOError(e) }
}

impl From<ParseIntError> for ConfigError {
    fn from(_: ParseIntError) -> ConfigError { ConfigError::InvalidParameter }
}

impl From<Utf8Error> for ConfigError {
    fn from(_: Utf8Error) -> ConfigError { ConfigError::InvalidParameter }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashMap;
    use std::fs::File;
    use std::fs::create_dir;
    use std::io::Write;

    use rand::random;

    use logger::Logger;
    use util::mstime;

    macro_rules! config {
        ($str: expr, $logger: expr) => ({
            let dirpath = format!("tmp/{}", mstime());
            let filepath = format!("{}/{}.conf", dirpath, random::<u64>());
            match create_dir("tmp") { _ => () }
            match create_dir(dirpath) { _ => () }
            match File::create(filepath.clone()).unwrap().write_all($str) { _ => () }
            let mut config = Config::new($logger);
            config.parsefile(filepath).unwrap();
            config
        })
    }

    #[test]
    fn parse_bind() {
        let config = config!(b"bind 1.2.3.4\nbind 5.6.7.8", Logger::null());
        assert_eq!(config.bind, vec!["1.2.3.4", "5.6.7.8"]);
        assert_eq!(config.port, 6379);
    }

    #[test]
    fn parse_port() {
        let config = config!(b"port 12345", Logger::null());
        assert_eq!(config.port, 12345);
        assert_eq!(config.addresses(), vec![("127.0.0.1".to_owned(), 12345)]);
    }

    #[test]
    fn parse_bind_port() {
        let config = config!(b"bind 127.0.0.1\nport 12345", Logger::null());
        assert_eq!(config.bind, vec!["127.0.0.1"]);
        assert_eq!(config.port, 12345);
    }

    #[test]
    fn parse_daemonize_yes() {
        let config = config!(b"daemonize yes", Logger::null());
        assert!(config.daemonize);
    }

    #[test]
    fn parse_daemonize_no() {
        let config = config!(b"daemonize no", Logger::null());
        assert!(!config.daemonize);
    }

    #[test]
    fn parse_active_rehashing_yes() {
        let config = config!(b"activerehashing yes", Logger::null());
        assert!(config.active_rehashing);
    }

    #[test]
    fn parse_active_rehashing_no() {
        let config = config!(b"activerehashing no", Logger::null());
        assert!(!config.active_rehashing);
    }

    #[test]
    fn parse_databases() {
        let config = config!(b"databases 20", Logger::null());
        assert_eq!(config.databases, 20);
    }

    #[test]
    fn parse_keepalive() {
        let config = config!(b"tcp-keepalive 123", Logger::null());
        assert_eq!(config.tcp_keepalive, 123);
    }

    #[test]
    fn parse_keepalive_quotes() {
        let config = config!(b"tcp-keepalive \"123\"", Logger::null());
        assert_eq!(config.tcp_keepalive, 123);
    }

    #[test]
    fn parse_set_max_intset_entries() {
        let config = config!(b"set-max-intset-entries 123456", Logger::null());
        assert_eq!(config.set_max_intset_entries, 123456);
    }

    #[test]
    fn parse_timeout() {
        let config = config!(b"timeout 23456", Logger::null());
        assert_eq!(config.timeout, 23456);
    }

    #[test]
    fn parse_unixsocket() {
        let config = config!(b"unixsocket /dev/null\nunixsocketperm 777", Logger::null());
        assert_eq!(config.unixsocket, Some("/dev/null".to_owned()));
        assert_eq!(config.unixsocketperm, 511);
    }

    #[test]
    fn parse_rename_commands() {
        let config = config!(b"rename-command C1 C2\nrename-command HELLO world", Logger::null());
        let mut h = HashMap::new();
        h.insert("c2".to_owned(), Some("c1".to_owned()));
        h.insert("c1".to_owned(), None);
        h.insert("world".to_owned(), Some("hello".to_owned()));
        h.insert("hello".to_owned(), None);
        assert_eq!(config.rename_commands, h);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
//
// 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.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.

mod utils;

use clap::Clap;
use utils::get_help;

#[test]
fn flatten() {
    #[derive(Clap, PartialEq, Debug)]
    struct Common {
        arg: i32,
    }

    #[derive(Clap, PartialEq, Debug)]
    struct Opt {
        #[clap(flatten)]
        common: Common,
    }
    assert_eq!(
        Opt {
            common: Common { arg: 42 }
        },
        Opt::parse_from(&["test", "42"])
    );
    assert!(Opt::try_parse_from(&["test"]).is_err());
    assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err());
}

#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn flatten_twice() {
    #[derive(Clap, PartialEq, Debug)]
    struct Common {
        arg: i32,
    }

    #[derive(Clap, PartialEq, Debug)]
    struct Opt {
        #[clap(flatten)]
        c1: Common,
        // Defines "arg" twice, so this should not work.
        #[clap(flatten)]
        c2: Common,
    }
    Opt::parse_from(&["test", "42", "43"]);
}

#[test]
fn flatten_in_subcommand() {
    #[derive(Clap, PartialEq, Debug)]
    struct Common {
        arg: i32,
    }

    #[derive(Clap, PartialEq, Debug)]
    struct Add {
        #[clap(short)]
        interactive: bool,
        #[clap(flatten)]
        common: Common,
    }

    #[derive(Clap, PartialEq, Debug)]
    enum Opt {
        Fetch {
            #[clap(short)]
            all: bool,
            #[clap(flatten)]
            common: Common,
        },

        Add(Add),
    }

    assert_eq!(
        Opt::Fetch {
            all: false,
            common: Common { arg: 42 }
        },
        Opt::parse_from(&["test", "fetch", "42"])
    );
    assert_eq!(
        Opt::Add(Add {
            interactive: true,
            common: Common { arg: 43 }
        }),
        Opt::parse_from(&["test", "add", "-i", "43"])
    );
}

#[derive(Clap, PartialEq, Debug)]
enum BaseCli {
    Command1(Command1),
}

#[derive(Clap, PartialEq, Debug)]
struct Command1 {
    arg1: i32,
    arg2: i32,
}

#[derive(Clap, PartialEq, Debug)]
struct Command2 {
    arg2: i32,
}

#[derive(Clap, PartialEq, Debug)]
enum Opt {
    #[clap(flatten)]
    BaseCli(BaseCli),
    Command2(Command2),
}

#[test]
fn merge_subcommands_with_flatten() {
    assert_eq!(
        Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 42, arg2: 44 })),
        Opt::parse_from(&["test", "command1", "42", "44"])
    );
    assert_eq!(
        Opt::Command2(Command2 { arg2: 43 }),
        Opt::parse_from(&["test", "command2", "43"])
    );
}

#[test]
fn update_subcommands_with_flatten() {
    let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
    opt.try_update_from(&["test", "command1", "42", "44"])
        .unwrap();
    assert_eq!(Opt::parse_from(&["test", "command1", "42", "44"]), opt);

    let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
    opt.try_update_from(&["test", "command1", "42"]).unwrap();
    assert_eq!(Opt::parse_from(&["test", "command1", "42", "14"]), opt);

    let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
    opt.try_update_from(&["test", "command2", "43"]).unwrap();
    assert_eq!(Opt::parse_from(&["test", "command2", "43"]), opt);
}

#[test]
fn flatten_with_doc_comment() {
    #[derive(Clap, Debug)]
    struct DaemonOpts {
        #[clap(short)]
        user: String,
        #[clap(short)]
        group: String,
    }

    #[derive(Clap, Debug)]
    #[clap(name = "basic")]
    struct Opt {
        /// A very important doc comment I just can't leave out!
        #[clap(flatten)]
        opts: DaemonOpts,
    }
}

#[test]
fn docstrings_ordering_with_multiple_clap() {
    /// This is the docstring for Flattened
    #[derive(Clap)]
    struct Flattened {
        #[clap(long)]
        foo: bool,
    }

    /// This is the docstring for Command
    #[derive(Clap)]
    struct Command {
        #[clap(flatten)]
        flattened: Flattened,
    }

    let short_help = get_help::<Command>();

    assert!(short_help.contains("This is the docstring for Command"));
}

#[test]
fn docstrings_ordering_with_multiple_clap_partial() {
    /// This is the docstring for Flattened
    #[derive(Clap)]
    struct Flattened {
        #[clap(long)]
        foo: bool,
    }

    #[derive(Clap)]
    struct Command {
        #[clap(flatten)]
        flattened: Flattened,
    }

    let short_help = get_help::<Command>();

    assert!(short_help.contains("This is the docstring for Flattened"));
}
<commit_msg>test(derive): Port structopt flatten coverage<commit_after>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
//
// 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.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.

mod utils;

use clap::Clap;
use utils::get_help;

#[test]
fn flatten() {
    #[derive(Clap, PartialEq, Debug)]
    struct Common {
        arg: i32,
    }

    #[derive(Clap, PartialEq, Debug)]
    struct Opt {
        #[clap(flatten)]
        common: Common,
    }
    assert_eq!(
        Opt {
            common: Common { arg: 42 }
        },
        Opt::parse_from(&["test", "42"])
    );
    assert!(Opt::try_parse_from(&["test"]).is_err());
    assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err());
}

#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn flatten_twice() {
    #[derive(Clap, PartialEq, Debug)]
    struct Common {
        arg: i32,
    }

    #[derive(Clap, PartialEq, Debug)]
    struct Opt {
        #[clap(flatten)]
        c1: Common,
        // Defines "arg" twice, so this should not work.
        #[clap(flatten)]
        c2: Common,
    }
    Opt::parse_from(&["test", "42", "43"]);
}

#[test]
fn flatten_in_subcommand() {
    #[derive(Clap, PartialEq, Debug)]
    struct Common {
        arg: i32,
    }

    #[derive(Clap, PartialEq, Debug)]
    struct Add {
        #[clap(short)]
        interactive: bool,
        #[clap(flatten)]
        common: Common,
    }

    #[derive(Clap, PartialEq, Debug)]
    enum Opt {
        Fetch {
            #[clap(short)]
            all: bool,
            #[clap(flatten)]
            common: Common,
        },

        Add(Add),
    }

    assert_eq!(
        Opt::Fetch {
            all: false,
            common: Common { arg: 42 }
        },
        Opt::parse_from(&["test", "fetch", "42"])
    );
    assert_eq!(
        Opt::Add(Add {
            interactive: true,
            common: Common { arg: 43 }
        }),
        Opt::parse_from(&["test", "add", "-i", "43"])
    );
}

#[derive(Clap, PartialEq, Debug)]
enum BaseCli {
    Command1(Command1),
}

#[derive(Clap, PartialEq, Debug)]
struct Command1 {
    arg1: i32,
    arg2: i32,
}

#[derive(Clap, PartialEq, Debug)]
struct Command2 {
    arg2: i32,
}

#[derive(Clap, PartialEq, Debug)]
enum Opt {
    #[clap(flatten)]
    BaseCli(BaseCli),
    Command2(Command2),
}

#[test]
fn merge_subcommands_with_flatten() {
    assert_eq!(
        Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 42, arg2: 44 })),
        Opt::parse_from(&["test", "command1", "42", "44"])
    );
    assert_eq!(
        Opt::Command2(Command2 { arg2: 43 }),
        Opt::parse_from(&["test", "command2", "43"])
    );
}

#[test]
fn update_subcommands_with_flatten() {
    let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
    opt.try_update_from(&["test", "command1", "42", "44"])
        .unwrap();
    assert_eq!(Opt::parse_from(&["test", "command1", "42", "44"]), opt);

    let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
    opt.try_update_from(&["test", "command1", "42"]).unwrap();
    assert_eq!(Opt::parse_from(&["test", "command1", "42", "14"]), opt);

    let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
    opt.try_update_from(&["test", "command2", "43"]).unwrap();
    assert_eq!(Opt::parse_from(&["test", "command2", "43"]), opt);
}

#[test]
fn flatten_with_doc_comment() {
    #[derive(Clap, PartialEq, Debug)]
    struct Common {
        /// This is an arg. Arg means "argument". Command line argument.
        arg: i32,
    }

    #[derive(Clap, PartialEq, Debug)]
    struct Opt {
        /// The very important comment that clippy had me put here.
        /// It knows better.
        #[clap(flatten)]
        common: Common,
    }
    assert_eq!(
        Opt {
            common: Common { arg: 42 }
        },
        Opt::parse_from(&["test", "42"])
    );

    let help = utils::get_help::<Opt>();
    assert!(help.contains("This is an arg."));
    assert!(!help.contains("The very important"));
}

#[test]
fn docstrings_ordering_with_multiple_clap() {
    /// This is the docstring for Flattened
    #[derive(Clap)]
    struct Flattened {
        #[clap(long)]
        foo: bool,
    }

    /// This is the docstring for Command
    #[derive(Clap)]
    struct Command {
        #[clap(flatten)]
        flattened: Flattened,
    }

    let short_help = get_help::<Command>();

    assert!(short_help.contains("This is the docstring for Command"));
}

#[test]
fn docstrings_ordering_with_multiple_clap_partial() {
    /// This is the docstring for Flattened
    #[derive(Clap)]
    struct Flattened {
        #[clap(long)]
        foo: bool,
    }

    #[derive(Clap)]
    struct Command {
        #[clap(flatten)]
        flattened: Flattened,
    }

    let short_help = get_help::<Command>();

    assert!(short_help.contains("This is the docstring for Flattened"));
}
<|endoftext|>


<commit_before>use core::sync::atomic::Ordering;

use arch;
use super::{contexts, Context, Status, CONTEXT_ID};

/// Switch to the next context
///
/// # Safety
///
/// Do not call this while holding locks!
pub unsafe fn switch() -> bool {
    use core::ops::DerefMut;

    // Set the global lock to avoid the unsafe operations below from causing issues
    while arch::context::CONTEXT_SWITCH_LOCK.compare_and_swap(false, true, Ordering::SeqCst) {
        arch::interrupt::pause();
    }

    let cpu_id = ::cpu_id();

    let from_ptr;
    let mut to_ptr = 0 as *mut Context;
    {
        let contexts = contexts();
        {
            let context_lock = contexts.current().expect("context::switch: not inside of context");
            let mut context = context_lock.write();
            from_ptr = context.deref_mut() as *mut Context;
        }

        let check_context = |context: &mut Context| -> bool {
            if context.cpu_id == None && cpu_id == 0 {
                context.cpu_id = Some(cpu_id);
                println!("{}: take {} {}", cpu_id, context.id, ::core::str::from_utf8_unchecked(&context.name.lock()));
            }

            if context.status == Status::Blocked && context.wake.is_some() {
                let wake = context.wake.expect("context::switch: wake not set");

                let current = arch::time::monotonic();
                if current.0 > wake.0 || (current.0 == wake.0 && current.1 >= wake.1) {
                    context.unblock();
                }
            }

            if context.cpu_id == Some(cpu_id) {
                if context.status == Status::Runnable && ! context.running {
                    return true;
                }
            }

            false
        };

        for (pid, context_lock) in contexts.iter() {
            if *pid > (*from_ptr).id {
                let mut context = context_lock.write();
                if check_context(&mut context) {
                    to_ptr = context.deref_mut() as *mut Context;
                    break;
                }
            }
        }

        if to_ptr as usize == 0 {
            for (pid, context_lock) in contexts.iter() {
                if *pid < (*from_ptr).id {
                    let mut context = context_lock.write();
                    if check_context(&mut context) {
                        to_ptr = context.deref_mut() as *mut Context;
                        break;
                    }
                }
            }
        }
    };

    if to_ptr as usize == 0 {
        // Unset global lock if no context found
        arch::context::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
        return false;
    }

    (&mut *from_ptr).running = false;
    (&mut *to_ptr).running = true;
    if let Some(ref stack) = (*to_ptr).kstack {
        arch::gdt::TSS.rsp[0] = (stack.as_ptr() as usize + stack.len() - 256) as u64;
    }
    CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);

    // Unset global lock before switch, as arch is only usable by the current CPU at this time
    arch::context::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);

    (&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);

    true
}
<commit_msg>remove take message<commit_after>use core::sync::atomic::Ordering;

use arch;
use super::{contexts, Context, Status, CONTEXT_ID};

/// Switch to the next context
///
/// # Safety
///
/// Do not call this while holding locks!
pub unsafe fn switch() -> bool {
    use core::ops::DerefMut;

    // Set the global lock to avoid the unsafe operations below from causing issues
    while arch::context::CONTEXT_SWITCH_LOCK.compare_and_swap(false, true, Ordering::SeqCst) {
        arch::interrupt::pause();
    }

    let cpu_id = ::cpu_id();

    let from_ptr;
    let mut to_ptr = 0 as *mut Context;
    {
        let contexts = contexts();
        {
            let context_lock = contexts.current().expect("context::switch: not inside of context");
            let mut context = context_lock.write();
            from_ptr = context.deref_mut() as *mut Context;
        }

        let check_context = |context: &mut Context| -> bool {
            if context.cpu_id == None && cpu_id == 0 {
                context.cpu_id = Some(cpu_id);
                // println!("{}: take {} {}", cpu_id, context.id, ::core::str::from_utf8_unchecked(&context.name.lock()));
            }

            if context.status == Status::Blocked && context.wake.is_some() {
                let wake = context.wake.expect("context::switch: wake not set");

                let current = arch::time::monotonic();
                if current.0 > wake.0 || (current.0 == wake.0 && current.1 >= wake.1) {
                    context.unblock();
                }
            }

            if context.cpu_id == Some(cpu_id) {
                if context.status == Status::Runnable && ! context.running {
                    return true;
                }
            }

            false
        };

        for (pid, context_lock) in contexts.iter() {
            if *pid > (*from_ptr).id {
                let mut context = context_lock.write();
                if check_context(&mut context) {
                    to_ptr = context.deref_mut() as *mut Context;
                    break;
                }
            }
        }

        if to_ptr as usize == 0 {
            for (pid, context_lock) in contexts.iter() {
                if *pid < (*from_ptr).id {
                    let mut context = context_lock.write();
                    if check_context(&mut context) {
                        to_ptr = context.deref_mut() as *mut Context;
                        break;
                    }
                }
            }
        }
    };

    if to_ptr as usize == 0 {
        // Unset global lock if no context found
        arch::context::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
        return false;
    }

    (&mut *from_ptr).running = false;
    (&mut *to_ptr).running = true;
    if let Some(ref stack) = (*to_ptr).kstack {
        arch::gdt::TSS.rsp[0] = (stack.as_ptr() as usize + stack.len() - 256) as u64;
    }
    CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);

    // Unset global lock before switch, as arch is only usable by the current CPU at this time
    arch::context::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);

    (&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);

    true
}
<|endoftext|>


<commit_before>// Implement data structures for a Huffman encoding tree:
//   http://rosettacode.org/wiki/Huffman_coding

extern crate core;
use std::collections::HashMap;
use std::collections::priority_queue::PriorityQueue;

// Each HNode has a weight, representing the sum of the frequencies for all its
// children. It is either a leaf (containing a character), or a HTree
// (containing two children)
struct HNode {
    weight: int,
    item: HTreeOrHLeaf,
}

enum HTreeOrHLeaf {
    HTree(HTreeData),
    HLeaf(char),
}

struct HTreeData {
    left: Box<HNode>,
    right: Box<HNode>,
}

// Implementing comparison traits (Ord and all its dependencies) such that
// the HNode with the greatest weight is the smallest in a comparison. Basically
// reversing all the comparison operators.
impl Ord for HNode {
    fn cmp(&self, other: &HNode) -> Ordering {
        match self.weight.cmp(&other.weight) {
            Less    => Greater,
            Equal   => Equal,
            Greater => Less,
        }
    }
}

impl PartialOrd for HNode {
    fn partial_cmp(&self, other: &HNode) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Eq for HNode {}
impl PartialEq for HNode {
    fn eq(&self, other: &HNode) -> bool {
        self.weight == other.weight
    }
}

// Takes a non-empty string (function will fail if string is empty) and computes
// the Huffman encoding tree for that string.
fn huffman_tree(input: &str) -> HNode {
    // 1. Loop through all the characters in that string, adding them to a HashMap
    //    of character to frequency.
    let mut freq = HashMap::new();
    for ch in input.chars() {
        freq.insert_or_update_with(ch, 1, |_k, v: &mut int| {*v += 1;});
    }

    // 2. For each (character, frequency) pair in the HashMap, add a Leaf to a
    //    PriorityQueue
    let mut queue = PriorityQueue::<HNode>::new();
    for (ch, freq) in freq.iter() {
        let new_node = HNode{
            weight: *freq,
            item: HLeaf(*ch),
        };
        queue.push(new_node);
    }

    // 3. Pop two items with the least weight from the queue, combine them into
    //    a tree as children. The parent node's weight is the sum of the
    //    children's weight. Continue until one item is left on the queue, and
    //    return that item.
    while queue.len() > 1 {
        let item1 = queue.pop().unwrap();
        let item2 = queue.pop().unwrap();
        let new_node = HNode {
            weight: item1.weight + item2.weight,
            item: HTree(HTreeData{
                left: box item1,
                right: box item2,
            }),
        };
        queue.push(new_node);
    }
    queue.pop().unwrap()
}

// Takes a Huffman Tree, traverse it and build a table with each character and
// its encoding string.
fn build_encoding_table(tree: &HNode,
                      table: &mut HashMap<char,String>,
                      startStr: &str) {
    match tree.item {
        HTree(ref data) => {
            build_encoding_table(&*data.left, table,
                               String::from_str(startStr).append("0").as_slice());
            build_encoding_table(&*data.right, table,
                               String::from_str(startStr).append("1").as_slice());
        },
        HLeaf(ch)   => {table.insert(ch, String::from_str(startStr));}
    };
}

// Attempts to construct a tree, and test that the construction is successful
//    7
//   ----
//  /    \
// 4:'4'  3
//      -----
//     /     \
//    2:'2'  1:'1'
#[test]
fn test_tree_construction() {
    let to_encode = "4444221";
    let tree = huffman_tree(to_encode);
    assert!(tree.weight == 7);
    let children = match tree.item {
        HTree(data) => data,
        HLeaf(_)    => fail!("Tree Missing Children!"),
    };
    let left  = &children.left;
    let right = &children.right;
    assert!(right.weight == 4);
    assert!(left.weight == 3);
    let right_char = match right.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    assert!(right_char == '4');
    let children = match left.item {
        HTree(ref data) => data,
        HLeaf(_)    => fail!("Tree Missing Children!"),
    };
    let left  = &children.left;
    let right = &children.right;
    let left_char = match left.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    let right_char = match right.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    match (left.weight, right.weight) {
        (1, 2) => {
            assert!(left_char == '1');
            assert!(right_char == '2');
        },
        (2, 1) => {
            assert!(left_char == '2');
            assert!(right_char == '1');
        },
        (_, _) => {
            fail!("Incorrect Leaf Nodes");
        }
    };
}

#[test]
// Constructs a table:
//  '4': 1
//  '2': 01 OR 00
//  '1': 00    01
// And tests that the table was correctly constructed
fn test_table_construction() {
    let to_encode = "4444221";
    let tree = huffman_tree(to_encode);
    let mut table = HashMap::<char,String>::new();
    build_encoding_table(&tree, &mut table, "");
    let one  = table.get(&'1').as_slice();
    let two  = table.get(&'2').as_slice();
    let four = table.get(&'4').as_slice();
    assert!(four == "1");
    assert!((one == "01" && two == "00") ||
            (one == "00" && two == "01"));
}

#[cfg(not(test))]
fn main() {
    let to_encode = "this is an example for huffman encoding";
    let tree = huffman_tree(to_encode);
    let mut table = HashMap::<char,String>::new();
    build_encoding_table(&tree, &mut table, "");

    for (ch, encoding) in table.iter() {
        println!("{}: {}", *ch, encoding);
    }
}
<commit_msg>Fix calls to deprecated get function<commit_after>// Implement data structures for a Huffman encoding tree:
//   http://rosettacode.org/wiki/Huffman_coding

extern crate core;
use std::collections::HashMap;
use std::collections::priority_queue::PriorityQueue;

// Each HNode has a weight, representing the sum of the frequencies for all its
// children. It is either a leaf (containing a character), or a HTree
// (containing two children)
struct HNode {
    weight: int,
    item: HTreeOrHLeaf,
}

enum HTreeOrHLeaf {
    HTree(HTreeData),
    HLeaf(char),
}

struct HTreeData {
    left: Box<HNode>,
    right: Box<HNode>,
}

// Implementing comparison traits (Ord and all its dependencies) such that
// the HNode with the greatest weight is the smallest in a comparison. Basically
// reversing all the comparison operators.
impl Ord for HNode {
    fn cmp(&self, other: &HNode) -> Ordering {
        match self.weight.cmp(&other.weight) {
            Less    => Greater,
            Equal   => Equal,
            Greater => Less,
        }
    }
}

impl PartialOrd for HNode {
    fn partial_cmp(&self, other: &HNode) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Eq for HNode {}
impl PartialEq for HNode {
    fn eq(&self, other: &HNode) -> bool {
        self.weight == other.weight
    }
}

// Takes a non-empty string (function will fail if string is empty) and computes
// the Huffman encoding tree for that string.
fn huffman_tree(input: &str) -> HNode {
    // 1. Loop through all the characters in that string, adding them to a HashMap
    //    of character to frequency.
    let mut freq = HashMap::new();
    for ch in input.chars() {
        freq.insert_or_update_with(ch, 1, |_k, v: &mut int| {*v += 1;});
    }

    // 2. For each (character, frequency) pair in the HashMap, add a Leaf to a
    //    PriorityQueue
    let mut queue = PriorityQueue::<HNode>::new();
    for (ch, freq) in freq.iter() {
        let new_node = HNode{
            weight: *freq,
            item: HLeaf(*ch),
        };
        queue.push(new_node);
    }

    // 3. Pop two items with the least weight from the queue, combine them into
    //    a tree as children. The parent node's weight is the sum of the
    //    children's weight. Continue until one item is left on the queue, and
    //    return that item.
    while queue.len() > 1 {
        let item1 = queue.pop().unwrap();
        let item2 = queue.pop().unwrap();
        let new_node = HNode {
            weight: item1.weight + item2.weight,
            item: HTree(HTreeData{
                left: box item1,
                right: box item2,
            }),
        };
        queue.push(new_node);
    }
    queue.pop().unwrap()
}

// Takes a Huffman Tree, traverse it and build a table with each character and
// its encoding string.
fn build_encoding_table(tree: &HNode,
                      table: &mut HashMap<char,String>,
                      startStr: &str) {
    match tree.item {
        HTree(ref data) => {
            build_encoding_table(&*data.left, table,
                               String::from_str(startStr).append("0").as_slice());
            build_encoding_table(&*data.right, table,
                               String::from_str(startStr).append("1").as_slice());
        },
        HLeaf(ch)   => {table.insert(ch, String::from_str(startStr));}
    };
}

// Attempts to construct a tree, and test that the construction is successful
//    7
//   ----
//  /    \
// 4:'4'  3
//      -----
//     /     \
//    2:'2'  1:'1'
#[test]
fn test_tree_construction() {
    let to_encode = "4444221";
    let tree = huffman_tree(to_encode);
    assert!(tree.weight == 7);
    let children = match tree.item {
        HTree(data) => data,
        HLeaf(_)    => fail!("Tree Missing Children!"),
    };
    let left  = &children.left;
    let right = &children.right;
    assert!(right.weight == 4);
    assert!(left.weight == 3);
    let right_char = match right.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    assert!(right_char == '4');
    let children = match left.item {
        HTree(ref data) => data,
        HLeaf(_)    => fail!("Tree Missing Children!"),
    };
    let left  = &children.left;
    let right = &children.right;
    let left_char = match left.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    let right_char = match right.item {
        HTree(_)  => fail!("Node is not Leaf Node!"),
        HLeaf(ch) => ch,
    };
    match (left.weight, right.weight) {
        (1, 2) => {
            assert!(left_char == '1');
            assert!(right_char == '2');
        },
        (2, 1) => {
            assert!(left_char == '2');
            assert!(right_char == '1');
        },
        (_, _) => {
            fail!("Incorrect Leaf Nodes");
        }
    };
}

#[test]
// Constructs a table:
//  '4': 1
//  '2': 01 OR 00
//  '1': 00    01
// And tests that the table was correctly constructed
fn test_table_construction() {
    let to_encode = "4444221";
    let tree = huffman_tree(to_encode);
    let mut table = HashMap::<char,String>::new();
    build_encoding_table(&tree, &mut table, "");
    let one  = table['1'].as_slice();
    let two  = table['2'].as_slice();
    let four = table['4'].as_slice();
    assert!(four == "1");
    assert!((one == "01" && two == "00") ||
            (one == "00" && two == "01"));
}

#[cfg(not(test))]
fn main() {
    let to_encode = "this is an example for huffman encoding";
    let tree = huffman_tree(to_encode);
    let mut table = HashMap::<char,String>::new();
    build_encoding_table(&tree, &mut table, "");

    for (ch, encoding) in table.iter() {
        println!("{}: {}", *ch, encoding);
    }
}
<|endoftext|>