<commit_before>use ansi_term::Style;
use fs::File;
use info::filetype::FileExtensions;
use output::file_name::FileStyle;

pub trait FileIcon {
    fn icon_file(&self, file: &File) -> Option<char>;
}

pub enum Icons {
    Audio,
    Image,
    Video,
}

impl Icons {
    pub fn value(&self) -> char {
        match *self {
            Icons::Audio => '\u{f001}',
            Icons::Image => '\u{f1c5}',
            Icons::Video => '\u{f03d}',
        }
    }
}

pub fn painted_icon(file: &File, style: &FileStyle) -> String {
    let file_icon = icon(&file).to_string();
    let painted = style.exts
            .colour_file(&file)
            .map_or(file_icon.to_string(), |c| {
                // Remove underline from icon
                if c.is_underline {
                    match c.foreground {
                        Some(color) => Style::from(color).paint(file_icon).to_string(),
                        None => Style::default().paint(file_icon).to_string(),
                    }
                } else {
                    c.paint(file_icon).to_string()
                }
            });
    format!("{} ", painted)
}

fn icon(file: &File) -> char {
    let extensions = Box::new(FileExtensions);
    if file.is_directory() { '\u{f115}' }
    else if let Some(icon) = extensions.icon_file(file) { icon }
    else {
        if let Some(ext) = file.ext.as_ref() {
            match ext.as_str() {
                "ai" => '\u{e7b4}',
                "android" => '\u{e70e}',
                "apple" => '\u{f179}',
                "avro" => '\u{e60b}',
                "clj" => '\u{e768}',
                "coffee" => '\u{f0f4}',
                "conf" => '\u{e615}',
                "cpp" => '\u{e61d}',
                "c" => '\u{e61e}',
                "h" => '\u{e61e}',
                "css" => '\u{e749}',
                "d" => '\u{e7af}',
                "dart" => '\u{e798}',
                "db" => '\u{f1c0}',
                "diff" => '\u{f440}',
                "patch" => '\u{f440}',
                "doc" => '\u{f1c2}',
                "ebook" => '\u{e28b}',
                "env" => '\u{f462}',
                "epub" => '\u{e28a}',
                "erl" => '\u{e7b1}',
                "font" => '\u{f031}',
                "gform" => '\u{f298}',
                "git" => '\u{f1d3}',
                "go" => '\u{e626}',
                "hs" => '\u{e777}',
                "html" => '\u{f13b}',
                "iml" => '\u{e7b5}',
                "java" => '\u{e204}',
                "js" => '\u{e74e}',
                "json" => '\u{e60b}',
                "jsx" => '\u{e7ba}',
                "less" => '\u{e758}',
                "log" => '\u{f18d}',
                "lua" => '\u{e620}',
                "md" => '\u{f48a}',
                "mustache" => '\u{e60f}',
                "npmignore" => '\u{e71e}',
                "pdf" => '\u{f1c1}',
                "php" => '\u{e73d}',
                "pl" => '\u{e769}',
                "ppt" => '\u{f1c4}',
                "psd" => '\u{e7b8}',
                "py" => '\u{e606}',
                "r" => '\u{f25d}',
                "rb" => '\u{e21e}',
                "rdb" => '\u{e76d}',
                "rs" => '\u{e7a8}',
                "rss" => '\u{f09e}',
                "rubydoc" => '\u{e73b}',
                "sass" => '\u{e603}',
                "scala" => '\u{e737}',
                "shell" => '\u{f489}',
                "sqlite3" => '\u{e7c4}',
                "styl" => '\u{e600}',
                "tex" => '\u{e600}',
                "ts" => '\u{e628}',
                "twig" => '\u{e61c}',
                "txt" => '\u{f15c}',
                "video" => '\u{f03d}',
                "vim" => '\u{e62b}',
                "xls" => '\u{f1c3}',
                "xml" => '\u{e619}',
                "yml" => '\u{f481}',
                "zip" => '\u{f410}',
                "deb" => '\u{e77d}',
                "rpm" => '\u{e7bb}',
                "exe" => '\u{e70f}',
                "msi" => '\u{e70f}',
                "dll" => '\u{e70f}',
                "sh" => '\u{f292}',
                "bash" => '\u{f292}',
                "zsh" => '\u{f292}',
                "fish" => '\u{f292}',
                "ini" => '\u{e615}',
                "toml" => '\u{e615}',
                "apk" => '\u{e70e}',
                "ttf" => '\u{f031}',
                "woff" => '\u{f031}',
                "woff2" => '\u{f031}',
                "otf" => '\u{f031}',
                _ => '\u{f15b}'
            }
        } else {
            '\u{f15b}'
        }
    }
}
<commit_msg>Add some icons for files<commit_after>use ansi_term::Style;
use fs::File;
use info::filetype::FileExtensions;
use output::file_name::FileStyle;

pub trait FileIcon {
    fn icon_file(&self, file: &File) -> Option<char>;
}

pub enum Icons {
    Audio,
    Image,
    Video,
}

impl Icons {
    pub fn value(&self) -> char {
        match *self {
            Icons::Audio => '\u{f001}',
            Icons::Image => '\u{f1c5}',
            Icons::Video => '\u{f03d}',
        }
    }
}

pub fn painted_icon(file: &File, style: &FileStyle) -> String {
    let file_icon = icon(&file).to_string();
    let painted = style.exts
            .colour_file(&file)
            .map_or(file_icon.to_string(), |c| {
                // Remove underline from icon
                if c.is_underline {
                    match c.foreground {
                        Some(color) => Style::from(color).paint(file_icon).to_string(),
                        None => Style::default().paint(file_icon).to_string(),
                    }
                } else {
                    c.paint(file_icon).to_string()
                }
            });
    format!("{} ", painted)
}

fn icon(file: &File) -> char {
    let extensions = Box::new(FileExtensions);
    if file.is_directory() { '\u{f115}' }
    else if let Some(icon) = extensions.icon_file(file) { icon }
    else {
        if let Some(ext) = file.ext.as_ref() {
            match ext.as_str() {
                "ai" => '\u{e7b4}',
                "android" => '\u{e70e}',
                "apple" => '\u{f179}',
                "avro" => '\u{e60b}',
                "clj" => '\u{e768}',
                "coffee" => '\u{f0f4}',
                "conf" => '\u{e615}',
                "cpp" => '\u{e61d}',
                "hpp" => '\u{e61d}',
                "c" => '\u{e61e}',
                "h" => '\u{e61e}',
                "cs" => '\u{f81a}',
                "css" => '\u{e749}',
                "d" => '\u{e7af}',
                "dart" => '\u{e798}',
                "db" => '\u{f1c0}',
                "diff" => '\u{f440}',
                "patch" => '\u{f440}',
                "doc" => '\u{f1c2}',
                "docx" => '\u{f1c2}',
                "odt" => '\u{f1c2}',
                "ebook" => '\u{e28b}',
                "env" => '\u{f462}',
                "epub" => '\u{e28a}',
                "erl" => '\u{e7b1}',
                "font" => '\u{f031}',
                "gform" => '\u{f298}',
                "git" => '\u{f1d3}',
                "go" => '\u{e626}',
                "hs" => '\u{e777}',
                "html" => '\u{f13b}',
                "iml" => '\u{e7b5}',
                "java" => '\u{e204}',
                "js" => '\u{e74e}',
                "mjs" => '\u{e74e}',
                "json" => '\u{e60b}',
                "jsx" => '\u{e7ba}',
                "vue" => '\u{fd42}',
                "node" => '\u{f898}',
                "less" => '\u{e758}',
                "log" => '\u{f18d}',
                "lua" => '\u{e620}',
                "md" => '\u{f48a}',
                "markdown" => '\u{f48a}',
                "mustache" => '\u{e60f}',
                "npmignore" => '\u{e71e}',
                "pdf" => '\u{f1c1}',
                "php" => '\u{e73d}',
                "pl" => '\u{e769}',
                "ppt" => '\u{f1c4}',
                "psd" => '\u{e7b8}',
                "py" => '\u{e606}',
                "r" => '\u{f25d}',
                "rb" => '\u{e21e}',
                "rdb" => '\u{e76d}',
                "rs" => '\u{e7a8}',
                "rss" => '\u{f09e}',
                "rubydoc" => '\u{e73b}',
                "sass" => '\u{e603}',
                "scala" => '\u{e737}',
                "shell" => '\u{f489}',
                "sqlite3" => '\u{e7c4}',
                "styl" => '\u{e600}',
                "tex" => '\u{e600}',
                "ts" => '\u{e628}',
                "tsx" => '\u{e628}',
                "twig" => '\u{e61c}',
                "txt" => '\u{f15c}',
                "video" => '\u{f03d}',
                "vim" => '\u{e62b}',
                "xml" => '\u{e619}',
                "yml" => '\u{f481}',
                "zip" => '\u{f410}',
                "deb" => '\u{e77d}',
                "rpm" => '\u{e7bb}',
                "exe" => '\u{e70f}',
                "msi" => '\u{e70f}',
                "dll" => '\u{e70f}',
                "sh" => '\u{e795}',
                "bash" => '\u{e795}',
                "zsh" => '\u{e795}',
                "fish" => '\u{e795}',
                "csh" => '\u{e795}',
                "ini" => '\u{e615}',
                "toml" => '\u{e615}',
                "apk" => '\u{e70e}',
                "ttf" => '\u{f031}',
                "woff" => '\u{f031}',
                "woff2" => '\u{f031}',
                "otf" => '\u{f031}',
                "csv" => '\u{f1c3}',
                "tsv" => '\u{f1c3}',
                "xls" => '\u{f1c3}',
                "xlsx" => '\u{f1c3}',
                "ods" => '\u{f1c3}',
                "so" => '\u{f17c}',
                "sql" => '\u{f1c0}',
                "jar" => '\u{e256}',
                "jad" => '\u{e256}',
                "war" => '\u{e256}',
                "groovy" => '\u{e775}',
                _ => '\u{f15b}'
            }
        } else {
            '\u{f15b}'
        }
    }
}
<|endoftext|>


<commit_before>// 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.

//! # Parser Nodes
//!
//! Parser nodes represent the grammar that is defined
//! by the currently permissible set of commands and their
//! parameters.

use std::rc::Rc;

/// Minimum priority.
pub const PRIORITY_MINIMUM: i32 = -10000;
/// The default priority for a parameter.
pub const PRIORITY_PARAMETER: i32 = -10;
/// The default priority.
pub const PRIORITY_DEFAULT: i32 = 0;

/// A node in the tree of commands and their parameters
/// used by the `Parser`.
pub trait Node {
    /// The data describing this node.
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields;

    /// The text used to identify this node in help text.
    /// This is typically the node name, either in plain
    /// form or decorated for parameters.
    fn help_symbol(&self) -> String {
        // XXX:Make this return a &String.
        self.node_data().help_symbol.clone()
    }

    /// Help text describing this node.
    fn help_text(&self) -> &Option<String> {
        &self.node_data().help_text
    }

    /// Hidden nodes are still found for matching, but are
    /// hidden from completion.
    fn hidden(&self) -> bool {
        self.node_data().hidden
    }

    /// The name of this node.
    fn name(&self) -> &String {
        &self.node_data().name
    }

    /// This priority of this node during matching and completion.
    fn priority(&self) -> i32 {
        self.node_data().priority
    }

    /// Nodes that are children of this node. Used to
    /// by the `Parser` during `advance`, `complete`, etc.
    fn successors(&self) -> &Vec<Rc<Node>> {
        &self.node_data().successors
    }
}

impl PartialEq for Node {
    /// Nodes are equal based on pointer equality.
    fn eq(&self, other: &Self) -> bool {
        self as *const _ == other as *const _
    }
}

/// A parse tree node.
#[doc(hidden)]
pub struct NodeFields {
    /// The name of this node.
    name: String,
    /// The text used to identify this node in help text.
    /// This is typically the node name, either in plain
    /// form or decorated for parameters.
    help_symbol: String,
    /// Help text describing this node.
    help_text: Option<String>,
    /// Hidden nodes are not completed. This doesn't modify matching.
    hidden: bool,
    /// Match and complete priority.
    priority: i32,
    /// Possible successor nodes. Collected while building.
    successors: Vec<Rc<Node>>,
}

/// The root of a command tree.
///
/// ```
/// use commands::parser::nodes::RootNode;
///
/// let root = RootNode::new(vec![]);
/// ```
pub struct RootNode {
    node_fields: NodeFields,
}

impl RootNode {
    /// Create a new `RootNode`
    pub fn new(successors: Vec<Rc<Node>>) -> Rc<Self> {
        Rc::new(RootNode {
            node_fields: NodeFields {
                name: "__root__".to_string(),
                help_symbol: "".to_string(),
                help_text: None,
                hidden: false,
                priority: PRIORITY_DEFAULT,
                successors: successors,
            },
        })
    }
}

impl Node for RootNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

/// A node representing a command.
pub struct CommandNode {
    node_fields: NodeFields,
    command_fields: CommandNodeFields,
}

struct CommandNodeFields {
    handler: Option<fn(&node: Node) -> ()>,
    parameters: Vec<Rc<ParameterNode>>,
}

impl CommandNode {
    /// Construct a new `CommandNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               handler: Option<fn(&node: Node) -> ()>,
               parameters: Vec<Rc<ParameterNode>>)
               -> Self {
        CommandNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: name.to_string(),
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            command_fields: CommandNodeFields {
                handler: handler,
                parameters: parameters,
            },
        }
    }
}
impl Node for CommandNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl CommandNode {
    /// The handler which is executed once this node has been accepted.
    pub fn handler(&self) -> Option<fn(&node: Node) -> ()> {
        self.command_fields.handler
    }

    /// Get the parameter nodes for this command.
    pub fn parameters(&self) -> &Vec<Rc<ParameterNode>> {
        &self.command_fields.parameters
    }
}

/// A wrapper node wraps another command.
///
/// This is used for the help command so that it can complete
/// normal commands.
///
/// The `successors` will be those of the wrapped node.
pub struct WrapperNode {
    node_fields: NodeFields,
    #[allow(dead_code)]
    command_fields: CommandNodeFields,
    root: Rc<Node>,
}

impl Node for WrapperNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }

    fn successors(&self) -> &Vec<Rc<Node>> {
        self.root.successors()
    }
}

/// A repeatable node is an internal helper for representing
/// nodes that can be repeated, like some parameters.
pub trait RepeatableNode: Node {
    /// Internal data for a repeatable node.
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields;

    /// Whether or not this node can be repeated. A repeated
    /// node can be `accept`ed multiple times.
    fn repeatable(&self) -> bool {
        self.repeatable_data().repeatable
    }

    /// If present, this node will no longer be `acceptable`.
    fn repeat_marker(&self) -> &Option<Rc<Node>> {
        &self.repeatable_data().repeat_marker
    }
}

/// The data for a repeatable node.
#[doc(hidden)]
pub struct RepeatableNodeFields {
    repeatable: bool,
    repeat_marker: Option<Rc<Node>>,
}

/// A node that represented the name portion of a named
/// parameter.
pub struct ParameterNameNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter: Rc<Node>,
}

impl Node for ParameterNameNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }

    fn help_symbol(&self) -> String {
        self.node_fields.name.clone() + " " + self.parameter.help_symbol().as_str()
    }
}

impl RepeatableNode for ParameterNameNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

/// Parameter nodes.
pub trait ParameterNode: Node + RepeatableNode {
    /// Internal data for a parameter node.
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields;

    /// A `required` parameter must be supplied for the
    /// command line being parsed to be valid.
    fn required(&self) -> bool {
        self.parameter_data().required
    }
}

/// Data for parameter nodes.
#[doc(hidden)]
pub struct ParameterNodeFields {
    required: bool,
}

/// A flag parameter node.
///
/// When implemented, this will only have a value of
/// true when it is present.
pub struct FlagParameterNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter_fields: ParameterNodeFields,
}

impl Node for FlagParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl RepeatableNode for FlagParameterNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

impl ParameterNode for FlagParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

impl FlagParameterNode {
    /// Construct a new `FlagParameterNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               required: bool)
               -> Self {
        let help_symbol = String::from("<") + name +
                          if repeatable {
            ">..."
        } else {
            ">"
        };
        FlagParameterNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: help_symbol,
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            repeatable_fields: RepeatableNodeFields {
                repeatable: repeatable,
                repeat_marker: repeat_marker,
            },
            parameter_fields: ParameterNodeFields { required: required },
        }
    }
}

/// A named parameter node.
pub struct NamedParameterNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter_fields: ParameterNodeFields,
}

impl Node for NamedParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl RepeatableNode for NamedParameterNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

impl ParameterNode for NamedParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

impl NamedParameterNode {
    /// Construct a new `NamedParameterNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               required: bool)
               -> Self {
        NamedParameterNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: name.to_string(),
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            repeatable_fields: RepeatableNodeFields {
                repeatable: repeatable,
                repeat_marker: repeat_marker,
            },
            parameter_fields: ParameterNodeFields { required: required },
        }
    }
}

/// A simple parameter node. This is only present in a command
/// line as a value.
pub struct SimpleParameterNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter_fields: ParameterNodeFields,
}

impl Node for SimpleParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl RepeatableNode for SimpleParameterNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

impl ParameterNode for SimpleParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

impl SimpleParameterNode {
    /// Construct a new `SimpleParameterNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               required: bool)
               -> Self {
        SimpleParameterNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: name.to_string(),
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            repeatable_fields: RepeatableNodeFields {
                repeatable: repeatable,
                repeat_marker: repeat_marker,
            },
            parameter_fields: ParameterNodeFields { required: required },
        }
    }
}
<commit_msg>CommandNode: merge |impl CommandNode| blocks.<commit_after>// 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.

//! # Parser Nodes
//!
//! Parser nodes represent the grammar that is defined
//! by the currently permissible set of commands and their
//! parameters.

use std::rc::Rc;

/// Minimum priority.
pub const PRIORITY_MINIMUM: i32 = -10000;
/// The default priority for a parameter.
pub const PRIORITY_PARAMETER: i32 = -10;
/// The default priority.
pub const PRIORITY_DEFAULT: i32 = 0;

/// A node in the tree of commands and their parameters
/// used by the `Parser`.
pub trait Node {
    /// The data describing this node.
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields;

    /// The text used to identify this node in help text.
    /// This is typically the node name, either in plain
    /// form or decorated for parameters.
    fn help_symbol(&self) -> String {
        // XXX:Make this return a &String.
        self.node_data().help_symbol.clone()
    }

    /// Help text describing this node.
    fn help_text(&self) -> &Option<String> {
        &self.node_data().help_text
    }

    /// Hidden nodes are still found for matching, but are
    /// hidden from completion.
    fn hidden(&self) -> bool {
        self.node_data().hidden
    }

    /// The name of this node.
    fn name(&self) -> &String {
        &self.node_data().name
    }

    /// This priority of this node during matching and completion.
    fn priority(&self) -> i32 {
        self.node_data().priority
    }

    /// Nodes that are children of this node. Used to
    /// by the `Parser` during `advance`, `complete`, etc.
    fn successors(&self) -> &Vec<Rc<Node>> {
        &self.node_data().successors
    }
}

impl PartialEq for Node {
    /// Nodes are equal based on pointer equality.
    fn eq(&self, other: &Self) -> bool {
        self as *const _ == other as *const _
    }
}

/// A parse tree node.
#[doc(hidden)]
pub struct NodeFields {
    /// The name of this node.
    name: String,
    /// The text used to identify this node in help text.
    /// This is typically the node name, either in plain
    /// form or decorated for parameters.
    help_symbol: String,
    /// Help text describing this node.
    help_text: Option<String>,
    /// Hidden nodes are not completed. This doesn't modify matching.
    hidden: bool,
    /// Match and complete priority.
    priority: i32,
    /// Possible successor nodes. Collected while building.
    successors: Vec<Rc<Node>>,
}

/// The root of a command tree.
///
/// ```
/// use commands::parser::nodes::RootNode;
///
/// let root = RootNode::new(vec![]);
/// ```
pub struct RootNode {
    node_fields: NodeFields,
}

impl RootNode {
    /// Create a new `RootNode`
    pub fn new(successors: Vec<Rc<Node>>) -> Rc<Self> {
        Rc::new(RootNode {
            node_fields: NodeFields {
                name: "__root__".to_string(),
                help_symbol: "".to_string(),
                help_text: None,
                hidden: false,
                priority: PRIORITY_DEFAULT,
                successors: successors,
            },
        })
    }
}

impl Node for RootNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

/// A node representing a command.
pub struct CommandNode {
    node_fields: NodeFields,
    command_fields: CommandNodeFields,
}

struct CommandNodeFields {
    handler: Option<fn(&node: Node) -> ()>,
    parameters: Vec<Rc<ParameterNode>>,
}

impl CommandNode {
    /// Construct a new `CommandNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               handler: Option<fn(&node: Node) -> ()>,
               parameters: Vec<Rc<ParameterNode>>)
               -> Self {
        CommandNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: name.to_string(),
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            command_fields: CommandNodeFields {
                handler: handler,
                parameters: parameters,
            },
        }
    }

    /// The handler which is executed once this node has been accepted.
    pub fn handler(&self) -> Option<fn(&node: Node) -> ()> {
        self.command_fields.handler
    }

    /// Get the parameter nodes for this command.
    pub fn parameters(&self) -> &Vec<Rc<ParameterNode>> {
        &self.command_fields.parameters
    }
}

impl Node for CommandNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

/// A wrapper node wraps another command.
///
/// This is used for the help command so that it can complete
/// normal commands.
///
/// The `successors` will be those of the wrapped node.
pub struct WrapperNode {
    node_fields: NodeFields,
    #[allow(dead_code)]
    command_fields: CommandNodeFields,
    root: Rc<Node>,
}

impl Node for WrapperNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }

    fn successors(&self) -> &Vec<Rc<Node>> {
        self.root.successors()
    }
}

/// A repeatable node is an internal helper for representing
/// nodes that can be repeated, like some parameters.
pub trait RepeatableNode: Node {
    /// Internal data for a repeatable node.
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields;

    /// Whether or not this node can be repeated. A repeated
    /// node can be `accept`ed multiple times.
    fn repeatable(&self) -> bool {
        self.repeatable_data().repeatable
    }

    /// If present, this node will no longer be `acceptable`.
    fn repeat_marker(&self) -> &Option<Rc<Node>> {
        &self.repeatable_data().repeat_marker
    }
}

/// The data for a repeatable node.
#[doc(hidden)]
pub struct RepeatableNodeFields {
    repeatable: bool,
    repeat_marker: Option<Rc<Node>>,
}

/// A node that represented the name portion of a named
/// parameter.
pub struct ParameterNameNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter: Rc<Node>,
}

impl Node for ParameterNameNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }

    fn help_symbol(&self) -> String {
        self.node_fields.name.clone() + " " + self.parameter.help_symbol().as_str()
    }
}

impl RepeatableNode for ParameterNameNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

/// Parameter nodes.
pub trait ParameterNode: Node + RepeatableNode {
    /// Internal data for a parameter node.
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields;

    /// A `required` parameter must be supplied for the
    /// command line being parsed to be valid.
    fn required(&self) -> bool {
        self.parameter_data().required
    }
}

/// Data for parameter nodes.
#[doc(hidden)]
pub struct ParameterNodeFields {
    required: bool,
}

/// A flag parameter node.
///
/// When implemented, this will only have a value of
/// true when it is present.
pub struct FlagParameterNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter_fields: ParameterNodeFields,
}

impl Node for FlagParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl RepeatableNode for FlagParameterNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

impl ParameterNode for FlagParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

impl FlagParameterNode {
    /// Construct a new `FlagParameterNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               required: bool)
               -> Self {
        let help_symbol = String::from("<") + name +
                          if repeatable {
            ">..."
        } else {
            ">"
        };
        FlagParameterNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: help_symbol,
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            repeatable_fields: RepeatableNodeFields {
                repeatable: repeatable,
                repeat_marker: repeat_marker,
            },
            parameter_fields: ParameterNodeFields { required: required },
        }
    }
}

/// A named parameter node.
pub struct NamedParameterNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter_fields: ParameterNodeFields,
}

impl Node for NamedParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl RepeatableNode for NamedParameterNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

impl ParameterNode for NamedParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

impl NamedParameterNode {
    /// Construct a new `NamedParameterNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               required: bool)
               -> Self {
        NamedParameterNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: name.to_string(),
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            repeatable_fields: RepeatableNodeFields {
                repeatable: repeatable,
                repeat_marker: repeat_marker,
            },
            parameter_fields: ParameterNodeFields { required: required },
        }
    }
}

/// A simple parameter node. This is only present in a command
/// line as a value.
pub struct SimpleParameterNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter_fields: ParameterNodeFields,
}

impl Node for SimpleParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl RepeatableNode for SimpleParameterNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

impl ParameterNode for SimpleParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

impl SimpleParameterNode {
    /// Construct a new `SimpleParameterNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               required: bool)
               -> Self {
        SimpleParameterNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: name.to_string(),
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            repeatable_fields: RepeatableNodeFields {
                repeatable: repeatable,
                repeat_marker: repeat_marker,
            },
            parameter_fields: ParameterNodeFields { required: required },
        }
    }
}
<|endoftext|>


<commit_before>use http::server::response::ResponseWriter;
use http::server::request::Request;
use http::headers::response::HeaderCollection;
use http::status::Status;

pub trait Response<'a>: Writer {
    fn request_mut<'a>(&'a self) -> &'a mut Request;
    fn headers_mut<'a>(&'a self) -> &'a mut Box<HeaderCollection>;
    fn status_mut<'a>(&'a self) -> &'a mut Status;

    fn request<'a>(&'a self) -> &'a Request;
    fn headers<'a>(&'a self) -> &'a HeaderCollection;
    fn status<'a>(&'a self) -> Status;

    fn from_http<'a>(&ResponseWriter<'a>) -> Self;
    fn to_http(&self, &mut ResponseWriter);
}
<commit_msg>(refactor) Refactored Response per rust-http limitations.<commit_after>use http::server::request::Request;
use http::headers::response::HeaderCollection;
use http::status::Status;

pub mod ironresponse;

pub trait Response<'a>: Writer {
    fn headers_mut<'a>(&'a mut self) -> &'a mut Box<HeaderCollection>;
    fn status_mut<'a>(&'a mut self) -> &'a mut Status;

    fn request<'a>(&'a self) -> &'a Request;
    fn headers<'a>(&'a self) -> &'a HeaderCollection;
    fn status<'a>(&'a self) -> &'a Status;
}
<|endoftext|>


<commit_before>use super::*;
use ::ast;

/// Represents the state of an RLE compiler from `ast::Instruction` to `Instruction`.
pub struct Compiler {
    instructions: Vec<Instruction>,
    buffer: (Command, usize),
}

impl Compiler {
    /// Creates a new RLE compiler.
    pub fn new() -> Self {
        Compiler {
            instructions: Vec::new(),
            buffer: (Command::Right, 0),
        }
    }

    /// Compiles the given sequence of instructions.
    pub fn compile(&mut self, program: &[ast::Instruction]) {
        for instruction in program {
            match *instruction {
                ast::Instruction::Op(op_code) => self.issue_op(op_code),
                ast::Instruction::Loop(ref body) => self.issue_loop(compile(body)),
            }
        }
    }

    /// Extracts the compiled program.
    pub fn into_program(mut self) -> Box<Program> {
        self.push_op();
        self.instructions.into_boxed_slice()
    }

    fn push_op(&mut self) {
        if self.buffer.1 > 0 {
            self.instructions.push(Instruction::Op(self.buffer));
            self.buffer = (Command::Right, 0);
        }
    }

    fn issue_op(&mut self, op_code: Command) {
        if op_code == self.buffer.0 {
            self.buffer.1 += 1;
        } else {
            self.push_op();
            self.buffer = (op_code, 1)
        }
    }

    fn issue_loop(&mut self, body: Box<Program>) {
        self.push_op();
        self.instructions.push(Instruction::Loop(body));
    }
}

pub fn compile(program: &[ast::Instruction]) -> Box<Program> {
    let mut compiler = Compiler::new();
    compiler.compile(program);
    compiler.into_program()
}

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

    #[test]
    fn right_compiles() {
        assert_compile(&[ast::mk_right()], &[mk_right(1)]);
    }

    #[test]
    fn three_rights_compile() {
        assert_compile(&[ast::mk_right(), ast::mk_right(), ast::mk_right()],
                       &[mk_right(3)]);
    }

    #[test]
    fn two_rights_two_ups_compile() {
        assert_compile(&[ast::mk_right(), ast::mk_right(), ast::mk_up(), ast::mk_up()],
                       &[mk_right(2), mk_up(2)]);
    }

    #[test]
    fn loop_compiles() {
        assert_compile(&[ast::mk_in(), ast::mk_loop(vec![ast::mk_right()]), ast::mk_in()],
                       &[mk_in(1), mk_loop(vec![mk_right(1)]), mk_in(1)]);

    }

    fn assert_compile(src: &[ast::Instruction], expected: &[Instruction]) {
        let actual = compile(src);
        assert_eq!(&*actual, expected);
    }
}
<commit_msg>Cleaned up.<commit_after>use super::*;
use ast;

/// Represents the state of an RLE compiler from `ast::Instruction` to `Instruction`.
pub struct Compiler {
    instructions: Vec<Instruction>,
    buffer: (Command, usize),
}

impl Compiler {
    /// Creates a new RLE compiler.
    pub fn new() -> Self {
        Compiler {
            instructions: Vec::new(),
            buffer: (Command::Right, 0),
        }
    }

    /// Compiles the given sequence of instructions.
    pub fn compile(&mut self, program: &[ast::Instruction]) {
        for instruction in program {
            match *instruction {
                ast::Instruction::Op(op_code) => self.issue_op(op_code),
                ast::Instruction::Loop(ref body) => self.issue_loop(compile(body)),
            }
        }
    }

    /// Extracts the compiled program.
    pub fn into_program(mut self) -> Box<Program> {
        self.push_op();
        self.instructions.into_boxed_slice()
    }

    fn push_op(&mut self) {
        if self.buffer.1 > 0 {
            self.instructions.push(Instruction::Op(self.buffer));
            self.buffer = (Command::Right, 0);
        }
    }

    fn issue_op(&mut self, op_code: Command) {
        if op_code == self.buffer.0 {
            self.buffer.1 += 1;
        } else {
            self.push_op();
            self.buffer = (op_code, 1)
        }
    }

    fn issue_loop(&mut self, body: Box<Program>) {
        self.push_op();
        self.instructions.push(Instruction::Loop(body));
    }
}

pub fn compile(program: &[ast::Instruction]) -> Box<Program> {
    let mut compiler = Compiler::new();
    compiler.compile(program);
    compiler.into_program()
}

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

    #[test]
    fn right_compiles() {
        assert_compile(&[ast::mk_right()], &[mk_right(1)]);
    }

    #[test]
    fn three_rights_compile() {
        assert_compile(&[ast::mk_right(), ast::mk_right(), ast::mk_right()],
                       &[mk_right(3)]);
    }

    #[test]
    fn two_rights_two_ups_compile() {
        assert_compile(&[ast::mk_right(), ast::mk_right(), ast::mk_up(), ast::mk_up()],
                       &[mk_right(2), mk_up(2)]);
    }

    #[test]
    fn loop_compiles() {
        assert_compile(&[ast::mk_in(), ast::mk_loop(vec![ast::mk_right()]), ast::mk_in()],
                       &[mk_in(1), mk_loop(vec![mk_right(1)]), mk_in(1)]);

    }

    fn assert_compile(src: &[ast::Instruction], expected: &[Instruction]) {
        let actual = compile(src);
        assert_eq!(&*actual, expected);
    }
}
<|endoftext|>


<commit_before>use math::Vector3;

pub struct Sphere {
    point: Vector3,
    radius: f64,
}

impl Sphere {
    pub fn new(p: Vector3, r: f64) -> Sphere {
        Sphere {
            point: p,
            radius: r,
        }
    }

    pub fn point(&self) -> Vector3 {
        self.point
    }

    pub fn radius(&self) -> f64 {
        self.radius
    }
}
<commit_msg>implement GeometricObject for Sphere<commit_after>use common;
use math::{Ray, Vector3};
use shape::GeometricObject;
use std::f64;

pub struct Sphere {
    center: Vector3,
    radius: f64,
}

impl Sphere {
    pub fn new(c: Vector3, r: f64) -> Sphere {
        Sphere {
            center: c,
            radius: r,
        }
    }

    pub fn center(&self) -> Vector3 {
        self.center
    }

    pub fn radius(&self) -> f64 {
        self.radius
    }
}

impl GeometricObject for Sphere {
    fn hit(&self, ray: &Ray) -> (bool, f64) {
        let delta = ray.origin() - self.center;
        let a = ray.direction().length_square();
        let b = 2.0 * delta * ray.direction();
        let c = delta.length_square() - self.radius.powi(2);

        let discriminant = b.powi(2) - 4.0 * a * c;

        if discriminant < 0.0 {
            return (false, f64::MAX);
        } else {
            let denominator = 2.0 * a;
            let root = discriminant.sqrt();

            let t = (-b - root) / denominator;
            if t > common::EPSILON {
                return (true, t);
            }

            let t = (-b + root) / denominator;
            if t > common::EPSILON {
                return (true, t);
            }
        }

        (false, f64::MAX)
    }
}

#[cfg(test)]
mod test {
    use super::Sphere;
    use math::vector3;
    use math::{Ray, Vector3};
    use shape::GeometricObject;
    use std::f64;

    #[test]
    fn test_hit() {
        let sphere = Sphere::new(vector3::ZERO, 1.0);

        let ray1 = Ray::new(Vector3::new(0.0, 1.0, 0.0), Vector3::new(0.0, 1.0, 0.0));
        let (hit1, t1) = sphere.hit(&ray1);
        assert!(!hit1);
        assert_eq!(t1, f64::MAX);

        let ray2 = Ray::new(vector3::ZERO, Vector3::new(0.0, 1.0, 0.0));
        let (hit2, t2) = sphere.hit(&ray2);
        assert!(hit2);
        assert_eq!(t2, 1.0);
   }
}<|endoftext|>


<commit_before>use crate::StrError;

/// Defines the class of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum GeoClass {
    /// Lines (segments) class
    Lin,

    /// Triangles class
    Tri,

    /// Quadrilaterals class
    Qua,

    /// Tetrahedra class
    Tet,

    /// Hexahedra class
    Hex,
}

/// Defines the kind of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum GeoKind {
    /// Line (segment) with 2 nodes (linear functions)
    Lin2 = 1_002,

    /// Line (segment) with 3 nodes (quadratic functions)
    Lin3 = 1_003,

    /// Line (segment) with 4 nodes (cubic functions)
    Lin4 = 1_004,

    /// Line (segment) with 5 nodes (quartic functions)
    Lin5 = 1_005,

    /// Triangle with 3 nodes (linear edges)
    Tri3 = 2_003,

    /// Triangle with 6 nodes (quadratic edges)
    Tri6 = 2_006,

    /// Triangle with 10 nodes (cubic edges; interior node)
    Tri10 = 2_010,

    /// Triangle with 15 nodes (quartic edges; interior nodes)
    Tri15 = 2_015,

    /// Quadrilateral with 4 nodes (linear edges)
    Qua4 = 2_004,

    /// Quadrilateral with 8 nodes (quadratic edges)
    Qua8 = 2_008,

    /// Quadrilateral with 9 nodes (quadratic edges; interior node)
    Qua9 = 2_009,

    /// Quadrilateral with 12 nodes (cubic edges)
    Qua12 = 2_012,

    /// Quadrilateral with 16 nodes (cubic edges; interior nodes)
    Qua16 = 2_016,

    /// Quadrilateral with 17 nodes (quartic edges; interior node)
    Qua17 = 2_017,

    /// Tetrahedron with 4 nodes (linear faces)
    Tet4 = 3_004,

    /// Tetrahedron with 10 nodes (quadratic faces)
    Tet10 = 3_010,

    /// Hexahedron with 8 nodes (bilinear faces)
    Hex8 = 3_008,

    /// Hexahedron with 20 nodes (quadratic faces)
    Hex20 = 3_020,
}

/// GeoNdim is the (local) space dimension of the geometric feature
pub type GeoNdim = usize;

/// GeoNnode is the number of nodes associated with a geometric feature
pub type GeoNnode = usize;

/// GeoKey identifies a geometric feature given its space dimension and number of nodes
pub type GeoKey = (GeoNdim, GeoNnode);

impl GeoKind {
    /// Holds all (geo_ndim,nnode) pairs
    pub const PAIRS: [(usize, usize); 18] = [
        // Lin
        (1, 2),
        (1, 3),
        (1, 4),
        (1, 5),
        // Tri
        (2, 3),
        (2, 6),
        (2, 10),
        (2, 15),
        // Qua
        (2, 4),
        (2, 8),
        (2, 9),
        (2, 12),
        (2, 16),
        (2, 17),
        // Tet
        (3, 4),
        (3, 10),
        // Hex
        (3, 8),
        (3, 20),
    ];

    /// Holds all enum values
    pub const VALUES: [Self; 18] = [
        // Lin
        Self::Lin2,
        Self::Lin3,
        Self::Lin4,
        Self::Lin5,
        // Tri
        Self::Tri3,
        Self::Tri6,
        Self::Tri10,
        Self::Tri15,
        // Qua
        Self::Qua4,
        Self::Qua8,
        Self::Qua9,
        Self::Qua12,
        Self::Qua16,
        Self::Qua17,
        // Tet
        Self::Tet4,
        Self::Tet10,
        // Hex
        Self::Hex8,
        Self::Hex20,
    ];
}

/// Returns the GeoClass and GeoKind for given geo_ndim and nnode
pub fn geo_class_and_kind(geo_ndim: usize, nnode: usize) -> Result<(GeoClass, GeoKind), StrError> {
    match (geo_ndim, nnode) {
        // Lin
        (1, 2) => Ok((GeoClass::Lin, GeoKind::Lin2)),
        (1, 3) => Ok((GeoClass::Lin, GeoKind::Lin3)),
        (1, 4) => Ok((GeoClass::Lin, GeoKind::Lin4)),
        (1, 5) => Ok((GeoClass::Lin, GeoKind::Lin5)),

        // Tri
        (2, 3) => Ok((GeoClass::Tri, GeoKind::Tri3)),
        (2, 6) => Ok((GeoClass::Tri, GeoKind::Tri6)),
        (2, 10) => Ok((GeoClass::Tri, GeoKind::Tri10)),
        (2, 15) => Ok((GeoClass::Tri, GeoKind::Tri15)),

        // Qua
        (2, 4) => Ok((GeoClass::Qua, GeoKind::Qua4)),
        (2, 8) => Ok((GeoClass::Qua, GeoKind::Qua8)),
        (2, 9) => Ok((GeoClass::Qua, GeoKind::Qua9)),
        (2, 12) => Ok((GeoClass::Qua, GeoKind::Qua12)),
        (2, 16) => Ok((GeoClass::Qua, GeoKind::Qua16)),
        (2, 17) => Ok((GeoClass::Qua, GeoKind::Qua17)),

        // Tet
        (3, 4) => Ok((GeoClass::Tet, GeoKind::Tet4)),
        (3, 10) => Ok((GeoClass::Tet, GeoKind::Tet10)),

        // Hex
        (3, 8) => Ok((GeoClass::Hex, GeoKind::Hex8)),
        (3, 20) => Ok((GeoClass::Hex, GeoKind::Hex20)),
        _ => Err("(geo_ndim,nnode) combination is invalid"),
    }
}

/// Returns the (min,max,delta) limits on the reference domain
///
/// # Tri and Tet
///
/// * `ξ_min` = 0.0
/// * `ξ_max` = 1.0
/// * `Δξ` = 1.0
///
/// # Lin, Qua, Hex
///
/// * `ξ_min` = -1.0
/// * `ξ_max` = +1.0
/// * `Δξ` = 2.0
#[inline]
pub fn ref_domain_limits(class: GeoClass) -> (f64, f64, f64) {
    if class == GeoClass::Tri || class == GeoClass::Tet {
        (0.0, 1.0, 1.0)
    } else {
        (-1.0, 1.0, 2.0)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::{
        shapes::{geo_class_and_kind, GeoClass, GeoKind},
        StrError,
    };
    use std::collections::HashSet;

    #[test]
    fn derive_works() {
        let class = GeoClass::Tri.clone();
        let kind = GeoKind::Tri6.clone();
        let classes = HashSet::from([GeoClass::Tri, GeoClass::Qua]);
        let kinds = HashSet::from([GeoKind::Tri3, GeoKind::Qua4]);
        assert_eq!(class, GeoClass::Tri);
        assert_eq!(kind, GeoKind::Tri6);
        assert_eq!(format!("{:?}", class), "Tri");
        assert_eq!(format!("{:?}", kind), "Tri6");
        assert_eq!(classes.contains(&GeoClass::Tri), true);
        assert_eq!(kinds.contains(&GeoKind::Tri3), true);
    }

    #[test]
    fn data_is_consistent() -> Result<(), StrError> {
        for kind in GeoKind::VALUES {
            match kind {
                // Lin
                GeoKind::Lin2 => {
                    assert_eq!(geo_class_and_kind(1, 2)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin3 => {
                    assert_eq!(geo_class_and_kind(1, 3)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin4 => {
                    assert_eq!(geo_class_and_kind(1, 4)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin5 => {
                    assert_eq!(geo_class_and_kind(1, 5)?, (GeoClass::Lin, kind));
                }

                // Tri
                GeoKind::Tri3 => {
                    assert_eq!(geo_class_and_kind(2, 3)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri6 => {
                    assert_eq!(geo_class_and_kind(2, 6)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri10 => {
                    assert_eq!(geo_class_and_kind(2, 10)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri15 => {
                    assert_eq!(geo_class_and_kind(2, 15)?, (GeoClass::Tri, kind));
                }

                // Qua
                GeoKind::Qua4 => {
                    assert_eq!(geo_class_and_kind(2, 4)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua8 => {
                    assert_eq!(geo_class_and_kind(2, 8)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua9 => {
                    assert_eq!(geo_class_and_kind(2, 9)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua12 => {
                    assert_eq!(geo_class_and_kind(2, 12)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua16 => {
                    assert_eq!(geo_class_and_kind(2, 16)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua17 => {
                    assert_eq!(geo_class_and_kind(2, 17)?, (GeoClass::Qua, kind));
                }

                // Tet
                GeoKind::Tet4 => {
                    assert_eq!(geo_class_and_kind(3, 4)?, (GeoClass::Tet, kind));
                }
                GeoKind::Tet10 => {
                    assert_eq!(geo_class_and_kind(3, 10)?, (GeoClass::Tet, kind));
                }

                // Hex
                GeoKind::Hex8 => {
                    assert_eq!(geo_class_and_kind(3, 8)?, (GeoClass::Hex, kind));
                }
                GeoKind::Hex20 => {
                    assert_eq!(geo_class_and_kind(3, 20)?, (GeoClass::Hex, kind));
                }
            }
        }
        Ok(())
    }
}
<commit_msg>Remove unused enum GeoKey<commit_after>use crate::StrError;

/// Defines the class of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum GeoClass {
    /// Lines (segments) class
    Lin,

    /// Triangles class
    Tri,

    /// Quadrilaterals class
    Qua,

    /// Tetrahedra class
    Tet,

    /// Hexahedra class
    Hex,
}

/// Defines the kind of geometric shape
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum GeoKind {
    /// Line (segment) with 2 nodes (linear functions)
    Lin2 = 1_002,

    /// Line (segment) with 3 nodes (quadratic functions)
    Lin3 = 1_003,

    /// Line (segment) with 4 nodes (cubic functions)
    Lin4 = 1_004,

    /// Line (segment) with 5 nodes (quartic functions)
    Lin5 = 1_005,

    /// Triangle with 3 nodes (linear edges)
    Tri3 = 2_003,

    /// Triangle with 6 nodes (quadratic edges)
    Tri6 = 2_006,

    /// Triangle with 10 nodes (cubic edges; interior node)
    Tri10 = 2_010,

    /// Triangle with 15 nodes (quartic edges; interior nodes)
    Tri15 = 2_015,

    /// Quadrilateral with 4 nodes (linear edges)
    Qua4 = 2_004,

    /// Quadrilateral with 8 nodes (quadratic edges)
    Qua8 = 2_008,

    /// Quadrilateral with 9 nodes (quadratic edges; interior node)
    Qua9 = 2_009,

    /// Quadrilateral with 12 nodes (cubic edges)
    Qua12 = 2_012,

    /// Quadrilateral with 16 nodes (cubic edges; interior nodes)
    Qua16 = 2_016,

    /// Quadrilateral with 17 nodes (quartic edges; interior node)
    Qua17 = 2_017,

    /// Tetrahedron with 4 nodes (linear faces)
    Tet4 = 3_004,

    /// Tetrahedron with 10 nodes (quadratic faces)
    Tet10 = 3_010,

    /// Hexahedron with 8 nodes (bilinear faces)
    Hex8 = 3_008,

    /// Hexahedron with 20 nodes (quadratic faces)
    Hex20 = 3_020,
}

/// GeoNdim is the (local) space dimension of the geometric feature
pub type GeoNdim = usize;

/// GeoNnode is the number of nodes associated with a geometric feature
pub type GeoNnode = usize;

impl GeoKind {
    /// Holds all (geo_ndim,nnode) pairs
    pub const PAIRS: [(usize, usize); 18] = [
        // Lin
        (1, 2),
        (1, 3),
        (1, 4),
        (1, 5),
        // Tri
        (2, 3),
        (2, 6),
        (2, 10),
        (2, 15),
        // Qua
        (2, 4),
        (2, 8),
        (2, 9),
        (2, 12),
        (2, 16),
        (2, 17),
        // Tet
        (3, 4),
        (3, 10),
        // Hex
        (3, 8),
        (3, 20),
    ];

    /// Holds all enum values
    pub const VALUES: [Self; 18] = [
        // Lin
        Self::Lin2,
        Self::Lin3,
        Self::Lin4,
        Self::Lin5,
        // Tri
        Self::Tri3,
        Self::Tri6,
        Self::Tri10,
        Self::Tri15,
        // Qua
        Self::Qua4,
        Self::Qua8,
        Self::Qua9,
        Self::Qua12,
        Self::Qua16,
        Self::Qua17,
        // Tet
        Self::Tet4,
        Self::Tet10,
        // Hex
        Self::Hex8,
        Self::Hex20,
    ];
}

/// Returns the GeoClass and GeoKind for given geo_ndim and nnode
pub fn geo_class_and_kind(geo_ndim: usize, nnode: usize) -> Result<(GeoClass, GeoKind), StrError> {
    match (geo_ndim, nnode) {
        // Lin
        (1, 2) => Ok((GeoClass::Lin, GeoKind::Lin2)),
        (1, 3) => Ok((GeoClass::Lin, GeoKind::Lin3)),
        (1, 4) => Ok((GeoClass::Lin, GeoKind::Lin4)),
        (1, 5) => Ok((GeoClass::Lin, GeoKind::Lin5)),

        // Tri
        (2, 3) => Ok((GeoClass::Tri, GeoKind::Tri3)),
        (2, 6) => Ok((GeoClass::Tri, GeoKind::Tri6)),
        (2, 10) => Ok((GeoClass::Tri, GeoKind::Tri10)),
        (2, 15) => Ok((GeoClass::Tri, GeoKind::Tri15)),

        // Qua
        (2, 4) => Ok((GeoClass::Qua, GeoKind::Qua4)),
        (2, 8) => Ok((GeoClass::Qua, GeoKind::Qua8)),
        (2, 9) => Ok((GeoClass::Qua, GeoKind::Qua9)),
        (2, 12) => Ok((GeoClass::Qua, GeoKind::Qua12)),
        (2, 16) => Ok((GeoClass::Qua, GeoKind::Qua16)),
        (2, 17) => Ok((GeoClass::Qua, GeoKind::Qua17)),

        // Tet
        (3, 4) => Ok((GeoClass::Tet, GeoKind::Tet4)),
        (3, 10) => Ok((GeoClass::Tet, GeoKind::Tet10)),

        // Hex
        (3, 8) => Ok((GeoClass::Hex, GeoKind::Hex8)),
        (3, 20) => Ok((GeoClass::Hex, GeoKind::Hex20)),
        _ => Err("(geo_ndim,nnode) combination is invalid"),
    }
}

/// Returns the (min,max,delta) limits on the reference domain
///
/// # Tri and Tet
///
/// * `ξ_min` = 0.0
/// * `ξ_max` = 1.0
/// * `Δξ` = 1.0
///
/// # Lin, Qua, Hex
///
/// * `ξ_min` = -1.0
/// * `ξ_max` = +1.0
/// * `Δξ` = 2.0
#[inline]
pub fn ref_domain_limits(class: GeoClass) -> (f64, f64, f64) {
    if class == GeoClass::Tri || class == GeoClass::Tet {
        (0.0, 1.0, 1.0)
    } else {
        (-1.0, 1.0, 2.0)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::{
        shapes::{geo_class_and_kind, GeoClass, GeoKind},
        StrError,
    };
    use std::collections::HashSet;

    #[test]
    fn derive_works() {
        let class = GeoClass::Tri.clone();
        let kind = GeoKind::Tri6.clone();
        let classes = HashSet::from([GeoClass::Tri, GeoClass::Qua]);
        let kinds = HashSet::from([GeoKind::Tri3, GeoKind::Qua4]);
        assert_eq!(class, GeoClass::Tri);
        assert_eq!(kind, GeoKind::Tri6);
        assert_eq!(format!("{:?}", class), "Tri");
        assert_eq!(format!("{:?}", kind), "Tri6");
        assert_eq!(classes.contains(&GeoClass::Tri), true);
        assert_eq!(kinds.contains(&GeoKind::Tri3), true);
    }

    #[test]
    fn data_is_consistent() -> Result<(), StrError> {
        for kind in GeoKind::VALUES {
            match kind {
                // Lin
                GeoKind::Lin2 => {
                    assert_eq!(geo_class_and_kind(1, 2)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin3 => {
                    assert_eq!(geo_class_and_kind(1, 3)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin4 => {
                    assert_eq!(geo_class_and_kind(1, 4)?, (GeoClass::Lin, kind));
                }
                GeoKind::Lin5 => {
                    assert_eq!(geo_class_and_kind(1, 5)?, (GeoClass::Lin, kind));
                }

                // Tri
                GeoKind::Tri3 => {
                    assert_eq!(geo_class_and_kind(2, 3)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri6 => {
                    assert_eq!(geo_class_and_kind(2, 6)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri10 => {
                    assert_eq!(geo_class_and_kind(2, 10)?, (GeoClass::Tri, kind));
                }
                GeoKind::Tri15 => {
                    assert_eq!(geo_class_and_kind(2, 15)?, (GeoClass::Tri, kind));
                }

                // Qua
                GeoKind::Qua4 => {
                    assert_eq!(geo_class_and_kind(2, 4)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua8 => {
                    assert_eq!(geo_class_and_kind(2, 8)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua9 => {
                    assert_eq!(geo_class_and_kind(2, 9)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua12 => {
                    assert_eq!(geo_class_and_kind(2, 12)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua16 => {
                    assert_eq!(geo_class_and_kind(2, 16)?, (GeoClass::Qua, kind));
                }
                GeoKind::Qua17 => {
                    assert_eq!(geo_class_and_kind(2, 17)?, (GeoClass::Qua, kind));
                }

                // Tet
                GeoKind::Tet4 => {
                    assert_eq!(geo_class_and_kind(3, 4)?, (GeoClass::Tet, kind));
                }
                GeoKind::Tet10 => {
                    assert_eq!(geo_class_and_kind(3, 10)?, (GeoClass::Tet, kind));
                }

                // Hex
                GeoKind::Hex8 => {
                    assert_eq!(geo_class_and_kind(3, 8)?, (GeoClass::Hex, kind));
                }
                GeoKind::Hex20 => {
                    assert_eq!(geo_class_and_kind(3, 20)?, (GeoClass::Hex, kind));
                }
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 Ivo Wetzel

// 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.
use super::super::Config;

/// A structure containing stats data average of the course of one second.
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct Stats {

    /// Average number of bytes received over the last second.
    pub bytes_sent: u32,

    /// Average number of bytes received over the last second.
    pub bytes_received: u32

}

impl Stats {
    fn reset(&mut self) {
        self.bytes_sent = 0;
        self.bytes_received = 0;
    }
}

impl Default for Stats {
    fn default() -> Stats {
        Stats {
            bytes_sent: 0,
            bytes_received: 0
        }
    }
}

/// Structure to keep track of per second average stats of a Client or Server.
///
/// Uses a list of buckets and caluclates the average each time a new value is
/// pushed into the bucket list `O(1)`.
#[derive(Debug)]
pub struct StatsCollector {

    /// Internal tick value
    tick: u32,

    /// The collectors's configuration
    config: Config,

    /// Internal stat buckets for O(1) average calculation
    buckets: Vec<Stats>,

    /// Internal stat average for the current tick
    averages: Stats

}

impl StatsCollector {

    /// Creates a new stats object which averages incoming data over the given
    /// number of ticks per second.
    pub fn new(config: Config) -> StatsCollector {
        StatsCollector {
            tick: 0,
            config: config,
            buckets: (0..config.send_rate + 1).map(|_| {
                Stats::default()

            }).collect::<Vec<Stats>>(),
            averages: Stats::default()
        }
    }

    /// Overrides the collector's existing configuration.
    pub fn set_config(&mut self, config: Config) {
        self.config = config;
        self.buckets = (0..config.send_rate + 1).map(|_| {
            Stats::default()

        }).collect::<Vec<Stats>>()
    }

    /// Sets the number of bytes sent for the current tick.
    pub fn set_bytes_sent(&mut self, bytes: u32) {
        let old_index = (self.tick as i32 + 1) % (self.config.send_rate + 1) as i32;
        let old_bytes = self.buckets.get(old_index as usize).unwrap().bytes_sent;
        self.averages.bytes_sent = (self.averages.bytes_sent - old_bytes) + bytes;
        self.buckets.get_mut(self.tick as usize).unwrap().bytes_sent = bytes;
    }

    /// Sets the number of bytes received for the current tick.
    pub fn set_bytes_received(&mut self, bytes: u32) {
        let old_index = (self.tick as i32 + 1) % (self.config.send_rate + 1) as i32;
        let old_bytes = self.buckets.get(old_index as usize).unwrap().bytes_received;
        self.averages.bytes_received = (self.averages.bytes_received - old_bytes) + bytes;
        self.buckets.get_mut(self.tick as usize).unwrap().bytes_received = bytes;
    }

    /// Steps the internal tick value used for average calculation.
    pub fn tick(&mut self) {
        self.tick = (self.tick + 1) % (self.config.send_rate + 1);
    }

    /// Returns the calculated averages from the last tick.
    pub fn average(&self) -> Stats {
        self.averages
    }

    /// Resets the internal data used for average calculation, but does not
    /// reset the last calculated averages.
    pub fn reset(&mut self) {
        for d in self.buckets.iter_mut() {
            d.reset();
        }
    }

}

<commit_msg>Clean up stats code a bit.<commit_after>// Copyright (c) 2015-2016 Ivo Wetzel

// 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.
use super::super::Config;

/// A structure containing stats data average of the course of one second.
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct Stats {

    /// Average number of bytes received over the last second.
    pub bytes_sent: u32,

    /// Average number of bytes received over the last second.
    pub bytes_received: u32

}

impl Stats {
    fn reset(&mut self) {
        self.bytes_sent = 0;
        self.bytes_received = 0;
    }
}

impl Default for Stats {
    fn default() -> Stats {
        Stats {
            bytes_sent: 0,
            bytes_received: 0
        }
    }
}

/// Structure to keep track of per second average stats of a Client or Server.
///
/// Uses a list of buckets and caluclates the average each time a new value is
/// pushed into the bucket list `O(1)`.
#[derive(Debug)]
pub struct StatsCollector {

    /// Internal tick value
    tick: u32,

    /// The collectors's configuration
    config: Config,

    /// Internal stat buckets for O(1) average calculation
    buckets: Vec<Stats>,

    /// Internal stat average for the current tick
    averages: Stats

}

impl StatsCollector {

    /// Creates a new stats object which averages incoming data over the given
    /// number of ticks per second.
    pub fn new(config: Config) -> StatsCollector {
        StatsCollector {
            tick: 0,
            config: config,
            buckets: (0..config.send_rate + 1).map(|_| {
                Stats::default()

            }).collect::<Vec<Stats>>(),
            averages: Stats::default()
        }
    }

    /// Overrides the collector's existing configuration.
    pub fn set_config(&mut self, config: Config) {
        self.config = config;
        self.buckets = (0..config.send_rate + 1).map(|_| {
            Stats::default()

        }).collect::<Vec<Stats>>()
    }

    /// Sets the number of bytes sent for the current tick.
    pub fn set_bytes_sent(&mut self, bytes: u32) {
        let old_index = (self.tick as i32 + 1) % (self.config.send_rate + 1) as i32;
        let old_bytes = self.buckets[old_index as usize].bytes_sent;
        self.averages.bytes_sent = (self.averages.bytes_sent - old_bytes) + bytes;
        self.buckets[self.tick as usize].bytes_sent = bytes;
    }

    /// Sets the number of bytes received for the current tick.
    pub fn set_bytes_received(&mut self, bytes: u32) {
        let old_index = (self.tick as i32 + 1) % (self.config.send_rate + 1) as i32;
        let old_bytes = self.buckets[old_index as usize].bytes_received;
        self.averages.bytes_received = (self.averages.bytes_received - old_bytes) + bytes;
        self.buckets[self.tick as usize].bytes_received = bytes;
    }

    /// Steps the internal tick value used for average calculation.
    pub fn tick(&mut self) {
        self.tick = (self.tick + 1) % (self.config.send_rate + 1);
    }

    /// Returns the calculated averages from the last tick.
    pub fn average(&self) -> Stats {
        self.averages
    }

    /// Resets the internal data used for average calculation, but does not
    /// reset the last calculated averages.
    pub fn reset(&mut self) {
        for d in self.buckets.iter_mut() {
            d.reset();
        }
    }

}

<|endoftext|>


<commit_before>use syntax::core::keywords::Keywords;
use syntax::core::tokens;
use syntax::core::tokens::Token;
use syntax::core::punctuation;
use syntax::core::punctuation::Punctuations;

pub trait Tokenizer {
    fn get_tok(&mut self) -> Token;
}

// A Lexer that keeps track of the current line and column position
// as well as the position in the char input stream.
pub struct Lexer {
    /*****

    pub status of line and column number deprecated, please use get_tok_line(), get_tok_column()

    ******/
    pub line_number: uint,
    pub column_number: uint,
    buffer_pos: uint,
    line_start: uint,
    input: String
}

impl Tokenizer for Lexer {
    // Parse the file where it left off and return the next token
    fn get_tok(&mut self) -> Token {
        // ToDo: More lexing!
        loop {
            if self.eof() {
                return tokens::EOF;
            }

            self.consume_whitespace();

            return match self.next_char() {
                // Find Keywords and Identifiers
                a if a.is_alphabetic() || a == '_' => self.consume_identifier(),

                e if self.eof() => tokens::EOF,

                // Find ints, floats, hex, and bin numeric values
                n if n.is_digit() => self.consume_numeric(),

                // Count tabs: \n\t*
                '\n' => self.consume_tabs(),

                // Error: Found tabs without preceeding newline
                '\t' => {
                    self.consume_char();

                    tokens::Error("Found an out of place tab.".to_string())
                },

                // Find single char punctuations
                '(' | ')' | '[' | ']' | '{' | '}' |
                '.' | ',' | ':' | '<' | '>' | '~' | '=' => {
                    // Dumb: cant do self.single_punc_token(self.consume_char()) due to borrowing
                    // But the following works.
                    let ch = self.consume_char();

                    self.single_punc_token(ch)
                },

                // Find multi-char(+=, -=, ..) punctuations or not
                '+' | '-' | '*' | '/' | '%' => {
                    let ch = self.consume_char();

                    match self.next_char() {
                        '=' => {
                            let ch2 = self.consume_char();

                            self.multi_punc_token([ch, ch2])
                        },
                         _  => self.single_punc_token(ch)
                    }
                },

                '>' => {
                    self.consume_char();

                    match self.next_char() {
                        '>' => self.consume_comment(),
                         _  => self.single_punc_token('>')
                    }
                },

                ch => tokens::Error(format!("Unknown character '{}'.", ch).to_string())
            };
        }
    }
}

impl Lexer {
    // Create a new lexer instance
    pub fn new<B: Buffer>(mut fileReader: B) -> Lexer {
        Lexer {
            line_number: 1,
            column_number: 1,
            buffer_pos: 0,
            line_start: 0,
            input: fileReader.read_to_string().unwrap()
        }
    }

    // ToDo: figure out a way to change this to take an index
    pub fn current_line(&mut self) -> String {
        let tmp = self.buffer_pos;
        let mut result = String::new();

        self.buffer_pos = self.line_start;

        result.push_str(self.consume_while(|ch| match ch {
            '\n' => false,
            _    => true
        }).as_slice());

        self.buffer_pos = tmp;

        result
    }

    fn current_slice(&mut self) -> &str {
        self.input.as_slice().slice_from(self.buffer_pos)
    }

    // Gets the next char and sets the position forward in the buffer
    fn consume_char(&mut self) -> char {
        let ch = self.next_char();

        self.buffer_pos += 1;
        self.column_number += 1;

        if ch == '\n' {
            self.line_start = self.buffer_pos;
            self.line_number += 1;
            self.column_number = 1;
        }

        ch
    }

    // Gets the next char
    fn next_char(&self) -> char {
        return self.input.as_slice().char_at(self.buffer_pos);
    }

    // Determine if we hit the inevitable End of File
    fn eof(&self) -> bool {
        return self.buffer_pos >= self.input.len();
    }

    // Thanks to mbrubeck of Mozilla for this consume_while fn as
    // well eof() and next_char() examples :)
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();

        while !self.eof() && test(self.next_char()) {
            result.push_char(self.consume_char());
        }

        result
    }

    // Single char puncuations: (, [, ., ...
    fn single_punc_token(&mut self, ch: char) -> Token {
        tokens::Punctuation(match ch {
            '(' => punctuation::ParenOpen,
            ')' => punctuation::ParenClose,
            '[' => punctuation::SBracketOpen,
            ']' => punctuation::SBracketClose,
            '{' => punctuation::CBracketOpen,
            '}' => punctuation::CBracketClose,
            '.' => punctuation::Period,
            ',' => punctuation::Comma,
            ':' => punctuation::Colon,
            '>' => punctuation::GreaterThan,
            '<' => punctuation::LessThan,
            '+' => punctuation::Plus,
            '-' => punctuation::Minus,
            '*' => punctuation::Asterisk,
            '/' => punctuation::Slash,
            '%' => punctuation::Percent,
            '~' => punctuation::Tilde,
            '=' => punctuation::Equals,

            // Should never get here:
              _ => punctuation::Period
        })
    }

    // Multi char punctuations: +=, -=, ...
    fn multi_punc_token(&mut self, vec: &[char]) -> Token {
        let string = String::from_chars(vec);
        let punct = from_str::<Punctuations>(string.as_slice()).unwrap();

        tokens::Punctuation(punct)
    }

    // Consume non newline whitespace
    fn consume_whitespace(&mut self) {
        self.consume_while(|ch| match ch {
            '\n'                   => false,
            '\t'                   => false,
            w if w.is_whitespace() => true,
            _                      => false
        });
    }

    // Identifiers: [a-zA-Z_][a-zA-z0-9_]*
    fn consume_identifier(&mut self) -> Token {
        // Lexer will only let you start with alpha or undescore,
        // so there is no need to check for numeric start
        let ident = self.consume_while(|ch| match ch {
            a if a.is_alphanumeric() => true,
            '_'                      => true,
             _                       => false
        });

        match from_str::<Keywords>(ident.as_slice()) {
            Some(key) => tokens::Keyword(key),
            None      => tokens::Identifier(ident)
        }
    }

    // Determines what type of number it is and call the appropriate fn
    fn consume_numeric(&mut self) -> Token {
        let mut result = String::new();

        if self.current_slice().starts_with("0x") {
            // Found hexadecimal: 0x[0-9a-fA-F_]+

            self.buffer_pos += 2;
            result.push_str("0x");

            // Cant do += for String, and push_str looks better than
            // result = result + self.consume...
            result.push_str(self.consume_while(|ch| match ch {
                '0'..'9' | 'a'..'f' | 'A'..'F' => true,
                 _                             => false
            }).as_slice());

            // ToDo: Get valid suffix for hex. Same as int?

        } else if self.current_slice().starts_with("0b") {
            // Found binary: 0b[01_]+

            self.buffer_pos += 2;
            result.push_str("0b");

            // Formatting the same as the hex case above.
            result.push_str(self.consume_while(|ch| match ch {
                '0' | '1' | '_' => true,
                 _              => false
            }).as_slice());

            // ToDo: Get valid suffix for bin. Same as int?

        } else {
            // Found int: [0-9]+ or float: [0-9]+.[0-9]+

            result.push_str(self.consume_while(|ch| match ch {
                '0'..'9' => true,
                 _       => false
            }).as_slice());

            match self.next_char() {
                // Float decimal point:
                '.' => {
                    result.push_char(self.consume_char());

                    let fractional = self.consume_while(|ch| match ch {
                        '0'..'9' => true,
                         _       => false
                    });

                    if fractional.as_slice() == "" {
                        return tokens::Error("Invalid floating point number.".to_string());

                    } else {
                        result.push_str(fractional.as_slice());
                    }

                    // Float suffixes:
                    // ToDo: find f32, f64?
                },

                // Int suffixes:
                // ToDo: will we need other int sizes?
                'i' | 'u' => {
                    result.push_char(self.consume_char());

                    // Ensure there are no additional alpha chars
                    if self.next_char().is_alphabetic() {
                        return tokens::Error("Invalid suffix.".to_string());
                    }

                },

                // Ensure there are no additional alpha chars
                c if c.is_alphabetic() => {
                    return tokens::Error("Invalid suffix".to_string());
                },

                // Presumably any other remaining char is valid, ie punctuation {,[ etc
                _ => ()
            };
        }

        match result.as_slice() {
            "0x" => tokens::Error("Invalid hex value.".to_string()),
            "0b" => tokens::Error("Invalid binary value.".to_string()),
             _   => tokens::Numeric(result)
        }
    }

    fn consume_comment(&mut self) -> Token {
        let mut result = String::new();

        // Consume 2nd '>'
        self.consume_char();

        if self.next_char() == '>' {
            // Multiline comments must end in <<< else error
            let mut sequence = 0u;

            // Consume 3rd '>'
            self.consume_char();

            result.push_str(self.consume_while(ref |ch| match ch {
                '<' => {
                    sequence += 1;

                    if sequence == 3 {
                        return false;
                    }
                    true
                },
                 _  => {
                     sequence = 0;
                     true
                 }
            }).as_slice());

            // ToDo: eof check/no <<< found -> error
        }
        else {

            // Single line comments eat up anything until newline or eof
            result.push_str(self.consume_while(|ch| match ch {
                '\n' => false,
                _ => true
            }).as_slice());
        }

        // ToDo: Finish this

        tokens::Comment(result)
    }

    fn consume_tabs(&mut self) -> Token {
        let mut count = 0;

        // Consume the newline token, count tabs
        self.consume_char();
        self.consume_while(ref |ch| match ch {
            '\t' => {
                count += 1;
                true
            },
             _   => false
        });

        tokens::Indent(count)
    }
}
<commit_msg>> char wasnt actually missing. Combined two match lines.<commit_after>use syntax::core::keywords::Keywords;
use syntax::core::tokens;
use syntax::core::tokens::Token;
use syntax::core::punctuation;
use syntax::core::punctuation::Punctuations;

pub trait Tokenizer {
    fn get_tok(&mut self) -> Token;
}

// A Lexer that keeps track of the current line and column position
// as well as the position in the char input stream.
pub struct Lexer {
    /*****

    pub status of line and column number deprecated, please use get_tok_line(), get_tok_column()

    ******/
    pub line_number: uint,
    pub column_number: uint,
    buffer_pos: uint,
    line_start: uint,
    input: String
}

impl Tokenizer for Lexer {
    // Parse the file where it left off and return the next token
    fn get_tok(&mut self) -> Token {
        // ToDo: More lexing!
        loop {
            if self.eof() {
                return tokens::EOF;
            }

            self.consume_whitespace();

            return match self.next_char() {
                // Find Keywords and Identifiers
                a if a.is_alphabetic() || a == '_' => self.consume_identifier(),

                e if self.eof() => tokens::EOF,

                // Find ints, floats, hex, and bin numeric values
                n if n.is_digit() => self.consume_numeric(),

                // Count tabs: \n\t*
                '\n' => self.consume_tabs(),

                // Error: Found tabs without preceeding newline
                '\t' => {
                    self.consume_char();

                    tokens::Error("Found an out of place tab.".to_string())
                },

                // Find single char punctuations
                '(' | ')' | '[' | ']' | '{' | '}' |
                '.' | ',' | ':' | '<' | '~' | '=' => {
                    // Dumb: cant do self.single_punc_token(self.consume_char()) due to borrowing
                    // But the following works.
                    let ch = self.consume_char();

                    self.single_punc_token(ch)
                },

                // Find multi-char(+=, -=, ..) punctuations or not
                '+' | '-' | '*' | '/' | '%' => {
                    let ch = self.consume_char();

                    match self.next_char() {
                        '=' => {
                            let ch2 = self.consume_char();

                            self.multi_punc_token([ch, ch2])
                        },
                         _  => self.single_punc_token(ch)
                    }
                },

                '>' => {
                    self.consume_char();

                    match self.next_char() {
                        '>' => self.consume_comment(),
                         _  => self.single_punc_token('>')
                    }
                },

                ch => tokens::Error(format!("Unknown character '{}'.", ch).to_string())
            };
        }
    }
}

impl Lexer {
    // Create a new lexer instance
    pub fn new<B: Buffer>(mut fileReader: B) -> Lexer {
        Lexer {
            line_number: 1,
            column_number: 1,
            buffer_pos: 0,
            line_start: 0,
            input: fileReader.read_to_string().unwrap()
        }
    }

    // ToDo: figure out a way to change this to take an index
    pub fn current_line(&mut self) -> String {
        let tmp = self.buffer_pos;
        let mut result = String::new();

        self.buffer_pos = self.line_start;

        result.push_str(self.consume_while(|ch| match ch {
            '\n' => false,
            _    => true
        }).as_slice());

        self.buffer_pos = tmp;

        result
    }

    fn current_slice(&mut self) -> &str {
        self.input.as_slice().slice_from(self.buffer_pos)
    }

    // Gets the next char and sets the position forward in the buffer
    fn consume_char(&mut self) -> char {
        let ch = self.next_char();

        self.buffer_pos += 1;
        self.column_number += 1;

        if ch == '\n' {
            self.line_start = self.buffer_pos;
            self.line_number += 1;
            self.column_number = 1;
        }

        ch
    }

    // Gets the next char
    fn next_char(&self) -> char {
        return self.input.as_slice().char_at(self.buffer_pos);
    }

    // Determine if we hit the inevitable End of File
    fn eof(&self) -> bool {
        return self.buffer_pos >= self.input.len();
    }

    // Thanks to mbrubeck of Mozilla for this consume_while fn as
    // well eof() and next_char() examples :)
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();

        while !self.eof() && test(self.next_char()) {
            result.push_char(self.consume_char());
        }

        result
    }

    // Single char puncuations: (, [, ., ...
    fn single_punc_token(&mut self, ch: char) -> Token {
        tokens::Punctuation(match ch {
            '(' => punctuation::ParenOpen,
            ')' => punctuation::ParenClose,
            '[' => punctuation::SBracketOpen,
            ']' => punctuation::SBracketClose,
            '{' => punctuation::CBracketOpen,
            '}' => punctuation::CBracketClose,
            '.' => punctuation::Period,
            ',' => punctuation::Comma,
            ':' => punctuation::Colon,
            '>' => punctuation::GreaterThan,
            '<' => punctuation::LessThan,
            '+' => punctuation::Plus,
            '-' => punctuation::Minus,
            '*' => punctuation::Asterisk,
            '/' => punctuation::Slash,
            '%' => punctuation::Percent,
            '~' => punctuation::Tilde,
            '=' => punctuation::Equals,

            // Should never get here:
              _ => punctuation::Period
        })
    }

    // Multi char punctuations: +=, -=, ...
    fn multi_punc_token(&mut self, vec: &[char]) -> Token {
        let string = String::from_chars(vec);
        let punct = from_str::<Punctuations>(string.as_slice()).unwrap();

        tokens::Punctuation(punct)
    }

    // Consume non newline whitespace
    fn consume_whitespace(&mut self) {
        self.consume_while(|ch| match ch {
            '\n' | '\t'            => false,
            w if w.is_whitespace() => true,
            _                      => false
        });
    }

    // Identifiers: [a-zA-Z_][a-zA-z0-9_]*
    fn consume_identifier(&mut self) -> Token {
        // Lexer will only let you start with alpha or undescore,
        // so there is no need to check for numeric start
        let ident = self.consume_while(|ch| match ch {
            a if a.is_alphanumeric() => true,
            '_'                      => true,
             _                       => false
        });

        match from_str::<Keywords>(ident.as_slice()) {
            Some(key) => tokens::Keyword(key),
            None      => tokens::Identifier(ident)
        }
    }

    // Determines what type of number it is and call the appropriate fn
    fn consume_numeric(&mut self) -> Token {
        let mut result = String::new();

        if self.current_slice().starts_with("0x") {
            // Found hexadecimal: 0x[0-9a-fA-F_]+

            self.buffer_pos += 2;
            result.push_str("0x");

            // Cant do += for String, and push_str looks better than
            // result = result + self.consume...
            result.push_str(self.consume_while(|ch| match ch {
                '0'..'9' | 'a'..'f' | 'A'..'F' => true,
                 _                             => false
            }).as_slice());

            // ToDo: Get valid suffix for hex. Same as int?

        } else if self.current_slice().starts_with("0b") {
            // Found binary: 0b[01_]+

            self.buffer_pos += 2;
            result.push_str("0b");

            // Formatting the same as the hex case above.
            result.push_str(self.consume_while(|ch| match ch {
                '0' | '1' | '_' => true,
                 _              => false
            }).as_slice());

            // ToDo: Get valid suffix for bin. Same as int?

        } else {
            // Found int: [0-9]+ or float: [0-9]+.[0-9]+

            result.push_str(self.consume_while(|ch| match ch {
                '0'..'9' => true,
                 _       => false
            }).as_slice());

            match self.next_char() {
                // Float decimal point:
                '.' => {
                    result.push_char(self.consume_char());

                    let fractional = self.consume_while(|ch| match ch {
                        '0'..'9' => true,
                         _       => false
                    });

                    if fractional.as_slice() == "" {
                        return tokens::Error("Invalid floating point number.".to_string());

                    } else {
                        result.push_str(fractional.as_slice());
                    }

                    // Float suffixes:
                    // ToDo: find f32, f64?
                },

                // Int suffixes:
                // ToDo: will we need other int sizes?
                'i' | 'u' => {
                    result.push_char(self.consume_char());

                    // Ensure there are no additional alpha chars
                    if self.next_char().is_alphabetic() {
                        return tokens::Error("Invalid suffix.".to_string());
                    }

                },

                // Ensure there are no additional alpha chars
                c if c.is_alphabetic() => {
                    return tokens::Error("Invalid suffix".to_string());
                },

                // Presumably any other remaining char is valid, ie punctuation {,[ etc
                _ => ()
            };
        }

        match result.as_slice() {
            "0x" => tokens::Error("Invalid hex value.".to_string()),
            "0b" => tokens::Error("Invalid binary value.".to_string()),
             _   => tokens::Numeric(result)
        }
    }

    fn consume_comment(&mut self) -> Token {
        let mut result = String::new();

        // Consume 2nd '>'
        self.consume_char();

        if self.next_char() == '>' {
            // Multiline comments must end in <<< else error
            let mut sequence = 0u;

            // Consume 3rd '>'
            self.consume_char();

            result.push_str(self.consume_while(ref |ch| match ch {
                '<' => {
                    sequence += 1;

                    if sequence == 3 {
                        return false;
                    }
                    true
                },
                 _  => {
                     sequence = 0;
                     true
                 }
            }).as_slice());

            // ToDo: eof check/no <<< found -> error
        }
        else {

            // Single line comments eat up anything until newline or eof
            result.push_str(self.consume_while(|ch| match ch {
                '\n' => false,
                _ => true
            }).as_slice());
        }

        // ToDo: Finish this

        tokens::Comment(result)
    }

    fn consume_tabs(&mut self) -> Token {
        let mut count = 0;

        // Consume the newline token, count tabs
        self.consume_char();
        self.consume_while(ref |ch| match ch {
            '\t' => {
                count += 1;
                true
            },
             _   => false
        });

        tokens::Indent(count)
    }
}
<|endoftext|>


<commit_before>use std::str;

use traits::Interpretable;

pub const FACTOR_SRC: &'static [u8] = include_bytes!("../bf/factor.bf");

pub const HELLO_WORLD_SRC: &'static [u8] =
    b"++++++[>++++++++++++<-]>.\
      >++++++++++[>++++++++++<-]>+.\
      +++++++..+++.>++++[>+++++++++++<-]>.\
      <+++[>----<-]>.<<<<<+++[>+++++<-]>.\
      >>.+++.------.--------.>>+.";

pub fn assert_interpret<I: Interpretable + ?Sized>(program: &I, input: &[u8], output: &[u8]) {
    let actual_bytes = program.interpret_memory(None, input).unwrap();
    let actual = str::from_utf8(&actual_bytes).unwrap();
    let expected = str::from_utf8(output).unwrap();

    assert_eq!(actual, expected);
}
<commit_msg>Added assert_interpret_result for handling failure.<commit_after>use std::str;

use result::BfResult;
use traits::Interpretable;

pub const FACTOR_SRC: &'static [u8] = include_bytes!("../bf/factor.bf");

pub const HELLO_WORLD_SRC: &'static [u8] =
    b"++++++[>++++++++++++<-]>.\
      >++++++++++[>++++++++++<-]>+.\
      +++++++..+++.>++++[>+++++++++++<-]>.\
      <+++[>----<-]>.<<<<<+++[>+++++<-]>.\
      >>.+++.------.--------.>>+.";

pub fn assert_interpret<I: Interpretable + ?Sized>(program: &I, input: &[u8], output: &[u8]) {
    assert_interpret_result(program, input, Ok(output));
}

pub fn assert_interpret_result<I>(program: &I, input: &[u8], output: BfResult<&[u8]>)
    where I: Interpretable + ?Sized
{
    let actual_bytes = program.interpret_memory(None, input);
    let actual = actual_bytes.map(|bytes| str::from_utf8(&bytes).unwrap().to_owned());
    let expected = output.map(|bytes| str::from_utf8(bytes).unwrap().to_owned());

    assert_eq!(actual, expected);

}
<|endoftext|>