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

//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the [`commands::tokenizer`] module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The command parser consists of two important things:
//!
//! * A tree that represents the available commands and their arguments.
//!   This tree consists of instances of implementations of [`Node`] like
//!   [`CommandNode`], [`ParameterNode`] and [`RootNode`]. Construction of this
//!   tree is done with the help of [`CommandTree`], [`Command`] and
//!   [`Parameter`].
//! * A [`Parser`] that handles input and matches it against the command
//!   tree. This parser is intended to be short-lived and to just live
//!   for the duration of parsing and evaluating a single command line
//!   input.
//!
//! ## Building Nodes
//!
//! Building a tree of nodes for use with the parser is best done with
//! the [`CommandTree`] in conjunction with [`Command`] and [`Parameter`].
//!
//! Start by creating a mutable [`CommandTree`] instance:
//!
//! ```
//! use commands::parser::{CommandTree, Parser};
//!
//! let mut tree = CommandTree::new();
//! ```
//!
//! Then, add your commands and arguments, and finally,
//! call `finalize` on the tree to get back a [`RootNode`]
//! that can use be used with a [`Parser`].
//!
//! ```
//! use commands::parser::{Command, CommandTree, Parameter, Parser};
//!
//! let mut tree = CommandTree::new();
//! tree.command(Command::new("again")
//!                  .hidden(false)
//!                  .parameter(Parameter::new("test")
//!                                 .required(false)
//!                                 .help("This is just a test parameter.")));
//! let root = tree.finalize();
//! let mut parser = Parser::new(root);
//! ```
//!
//! [`commands::tokenizer`]: ../tokenizer/index.html
//! [`Command`]: struct.Command.html
//! [`CommandNode`]: struct.CommandNode.html
//! [`CommandTree`]: struct.CommandTree.html
//! [`Node`]: enum.Node.html
//! [`Parameter`]: struct.Parameter.html
//! [`ParameterNode`]: trait.ParameterNode.html
//! [`Parser`]: struct.Parser.html
//! [`RootNode`]: struct.RootNode.html

mod builder;
mod completion;
mod constants;
mod nodes;

// Re-export public API
pub use self::builder::{Command, CommandTree, Parameter};
pub use self::constants::ParameterKind;
pub use self::constants::{PRIORITY_DEFAULT, PRIORITY_MINIMUM, PRIORITY_PARAMETER};
pub use self::completion::{Completion, CompletionOption};
pub use self::nodes::{Node, NodeOps};
pub use self::nodes::{CommandNode, ParameterNameNode, ParameterNode, RootNode};

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use tokenizer::{Token, TokenType};

/// Command parser
///
/// The lifetime parameter `'text` refers to the lifetime of the
/// tokens passed into the parser. This is the same as the lifetime
/// of the text used to create the tokens.
///
/// When creating a `Parser`, you must give it an `Rc<RootNode>`.
/// [`RootNode`] instances should be created using a [`CommandTree`].
///
/// ```
/// use commands::parser::{Command, CommandTree, Parser};
///
/// let mut tree = CommandTree::new();
/// tree.command(Command::new("show"));
/// tree.command(Command::new("set"));
/// tree.command(Command::new("help"));
///
/// let mut parser = Parser::new(tree.finalize());
/// ```
///
/// The parser is constructed as a `mut`able object as most of
/// the methods on it will modify its state.
///
/// [`CommandTree`]: struct.CommandTree.html
/// ['RootNode`]: struct.RootNode.html
pub struct Parser<'text> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'text>>,
    commands: Vec<Rc<Node>>,
    parameters: HashMap<String, String>,
}

impl<'text> Parser<'text> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<Node>) -> Parser<'text> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// [`Completion`] and [`CompletionOption`]s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one [`Completion`] in the
    /// result vector. Each [`Completion`] will have one or more
    /// [`CompletionOption`] for each valid way that the value may be
    /// entered.
    ///
    /// ```
    /// use commands::parser::{Command, CommandTree, Parser};
    /// use commands::tokenizer::{Token, tokenize};
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show"));
    /// tree.command(Command::new("set"));
    /// tree.command(Command::new("help"));
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// // Completing now should have 3 options, 1 for each command.
    /// let comps = parser.complete(None);
    /// assert_eq!(comps.len(), 3);
    ///
    /// // But completing with a token for 'h' should have 1 option.
    /// if let Ok(tokens) = tokenize("h") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 1);
    ///   assert_eq!(comps[0].options.len(), 1);
    ///   assert_eq!(comps[0].options[0].option_string, "help");
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    ///
    /// // And completing for 's' should have 2 options.
    /// if let Ok(tokens) = tokenize("s") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 2);
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    /// ```
    ///
    /// [`Completion`]: struct.Completion.html
    /// [`CompletionOption`]: struct.CompletionOption.html
    pub fn complete(&self, token: Option<Token<'text>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.node().hidden && n.acceptable(self, n) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    ///
    /// ```
    /// use commands::parser::{Command, CommandTree, Parser};
    /// use commands::tokenizer::tokenize;
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show interface"));
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// if let Ok(tokens) = tokenize("show interface") {
    ///     parser.parse(tokens);
    /// }
    /// ```
    pub fn parse(&mut self, tokens: Vec<Token<'text>>) -> Result<(), ParseError<'text>> {
        for token in tokens {
            match token.token_type {
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'text>) -> Result<(), ParseError<'text>> {
        let acceptable = self.current_node
                             .successors()
                             .into_iter()
                             .filter(|n| n.acceptable(self, n))
                             .map(|n| n.clone())
                             .collect::<Vec<_>>();
        let matches = acceptable.clone()
                                .into_iter()
                                .filter(|n| n.matches(self, token))
                                .map(|n| n.clone())
                                .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = &matches[0];
                matching_node.accept(self, token, matching_node);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParseError::NoMatches(token, acceptable)),
            _ => Err(ParseError::AmbiguousMatch(token, matches)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    pub fn verify(&self) -> Result<(), VerifyError> {
        if let Some(&Node::Command(ref command)) = self.commands.first().map(|n| &**n) {
            for expected in &command.parameters {
                if let Node::Parameter(ref param) = **expected {
                    let name = &param.node.name;
                    if param.required && !self.parameters.contains_key(name) {
                        return Err(VerifyError::MissingParameter(name.clone()));
                    }
                } else {
                    unreachable!();
                }
            }
            Ok(())
        } else {
            Err(VerifyError::NoCommandAccepted)
        }
    }
}

/// Errors that calling `parse` on the `Parser` can raise.
#[derive(Clone)]
pub enum ParseError<'text> {
    /// There were no matches for the token.
    NoMatches(Token<'text>, Vec<Rc<Node>>),
    /// There was more than 1 possible match for the token.
    AmbiguousMatch(Token<'text>, Vec<Rc<Node>>),
}

impl<'text> fmt::Debug for ParseError<'text> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::NoMatches(token, _) => write!(f, "NoMatches({:?}, ...)", token),
            ParseError::AmbiguousMatch(token, _) => write!(f, "AmbiguousMatch({:?}, ...)", token),
        }
    }
}

impl<'text> Error for ParseError<'text> {
    fn description(&self) -> &str {
        match *self {
            ParseError::NoMatches(_, _) => "No match.",
            ParseError::AmbiguousMatch(_, _) => "Ambiguous match.",
        }
    }
}

impl<'text> fmt::Display for ParseError<'text> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Errors that calling `verify` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum VerifyError {
    /// No command has been accepted by the parser.
    NoCommandAccepted,
    /// A required parameter is missing.
    MissingParameter(String),
}

impl Error for VerifyError {
    fn description(&self) -> &str {
        match *self {
            VerifyError::NoCommandAccepted => "No command has been accepted by the parser.",
            VerifyError::MissingParameter(_) => "A required parameter is missing.",
        }
    }
}

impl fmt::Display for VerifyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

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

    #[test]
    #[should_panic]
    fn verify_signals_no_command() {
        let root = CommandTree::new().finalize();
        let parser = Parser::new(root);
        match parser.verify() {
            Err(VerifyError::NoCommandAccepted) => panic!(),
            _ => {}
        }
    }

    #[test]
    #[should_panic]
    fn parse_signals_no_matches() {
        let mut tree = CommandTree::new();
        tree.command(Command::new("show"));
        let mut parser = Parser::new(tree.finalize());
        if let Ok(tokens) = tokenize("h") {
            match parser.parse(tokens) {
                Err(ParseError::NoMatches(_, _)) => panic!(),
                _ => {}
            }
        }
    }

    #[test]
    #[should_panic]
    fn parse_signals_ambiguous_match() {
        let mut tree = CommandTree::new();
        tree.command(Command::new("show"));
        tree.command(Command::new("set"));
        let mut parser = Parser::new(tree.finalize());
        if let Ok(tokens) = tokenize("s") {
            match parser.parse(tokens) {
                Err(ParseError::AmbiguousMatch(_, _)) => panic!(),
                _ => {}
            }
        }
    }
}
<commit_msg>Export `TreeNode` as well since it should be public.<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.

//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the [`commands::tokenizer`] module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The command parser consists of two important things:
//!
//! * A tree that represents the available commands and their arguments.
//!   This tree consists of instances of implementations of [`Node`] like
//!   [`CommandNode`], [`ParameterNode`] and [`RootNode`]. Construction of this
//!   tree is done with the help of [`CommandTree`], [`Command`] and
//!   [`Parameter`].
//! * A [`Parser`] that handles input and matches it against the command
//!   tree. This parser is intended to be short-lived and to just live
//!   for the duration of parsing and evaluating a single command line
//!   input.
//!
//! ## Building Nodes
//!
//! Building a tree of nodes for use with the parser is best done with
//! the [`CommandTree`] in conjunction with [`Command`] and [`Parameter`].
//!
//! Start by creating a mutable [`CommandTree`] instance:
//!
//! ```
//! use commands::parser::{CommandTree, Parser};
//!
//! let mut tree = CommandTree::new();
//! ```
//!
//! Then, add your commands and arguments, and finally,
//! call `finalize` on the tree to get back a [`RootNode`]
//! that can use be used with a [`Parser`].
//!
//! ```
//! use commands::parser::{Command, CommandTree, Parameter, Parser};
//!
//! let mut tree = CommandTree::new();
//! tree.command(Command::new("again")
//!                  .hidden(false)
//!                  .parameter(Parameter::new("test")
//!                                 .required(false)
//!                                 .help("This is just a test parameter.")));
//! let root = tree.finalize();
//! let mut parser = Parser::new(root);
//! ```
//!
//! [`commands::tokenizer`]: ../tokenizer/index.html
//! [`Command`]: struct.Command.html
//! [`CommandNode`]: struct.CommandNode.html
//! [`CommandTree`]: struct.CommandTree.html
//! [`Node`]: enum.Node.html
//! [`Parameter`]: struct.Parameter.html
//! [`ParameterNode`]: trait.ParameterNode.html
//! [`Parser`]: struct.Parser.html
//! [`RootNode`]: struct.RootNode.html

mod builder;
mod completion;
mod constants;
mod nodes;

// Re-export public API
pub use self::builder::{Command, CommandTree, Parameter};
pub use self::constants::ParameterKind;
pub use self::constants::{PRIORITY_DEFAULT, PRIORITY_MINIMUM, PRIORITY_PARAMETER};
pub use self::completion::{Completion, CompletionOption};
pub use self::nodes::{Node, NodeOps, TreeNode};
pub use self::nodes::{CommandNode, ParameterNameNode, ParameterNode, RootNode};

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use tokenizer::{Token, TokenType};

/// Command parser
///
/// The lifetime parameter `'text` refers to the lifetime of the
/// tokens passed into the parser. This is the same as the lifetime
/// of the text used to create the tokens.
///
/// When creating a `Parser`, you must give it an `Rc<RootNode>`.
/// [`RootNode`] instances should be created using a [`CommandTree`].
///
/// ```
/// use commands::parser::{Command, CommandTree, Parser};
///
/// let mut tree = CommandTree::new();
/// tree.command(Command::new("show"));
/// tree.command(Command::new("set"));
/// tree.command(Command::new("help"));
///
/// let mut parser = Parser::new(tree.finalize());
/// ```
///
/// The parser is constructed as a `mut`able object as most of
/// the methods on it will modify its state.
///
/// [`CommandTree`]: struct.CommandTree.html
/// ['RootNode`]: struct.RootNode.html
pub struct Parser<'text> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'text>>,
    commands: Vec<Rc<Node>>,
    parameters: HashMap<String, String>,
}

impl<'text> Parser<'text> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<Node>) -> Parser<'text> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// [`Completion`] and [`CompletionOption`]s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one [`Completion`] in the
    /// result vector. Each [`Completion`] will have one or more
    /// [`CompletionOption`] for each valid way that the value may be
    /// entered.
    ///
    /// ```
    /// use commands::parser::{Command, CommandTree, Parser};
    /// use commands::tokenizer::{Token, tokenize};
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show"));
    /// tree.command(Command::new("set"));
    /// tree.command(Command::new("help"));
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// // Completing now should have 3 options, 1 for each command.
    /// let comps = parser.complete(None);
    /// assert_eq!(comps.len(), 3);
    ///
    /// // But completing with a token for 'h' should have 1 option.
    /// if let Ok(tokens) = tokenize("h") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 1);
    ///   assert_eq!(comps[0].options.len(), 1);
    ///   assert_eq!(comps[0].options[0].option_string, "help");
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    ///
    /// // And completing for 's' should have 2 options.
    /// if let Ok(tokens) = tokenize("s") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 2);
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    /// ```
    ///
    /// [`Completion`]: struct.Completion.html
    /// [`CompletionOption`]: struct.CompletionOption.html
    pub fn complete(&self, token: Option<Token<'text>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.node().hidden && n.acceptable(self, n) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    ///
    /// ```
    /// use commands::parser::{Command, CommandTree, Parser};
    /// use commands::tokenizer::tokenize;
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show interface"));
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// if let Ok(tokens) = tokenize("show interface") {
    ///     parser.parse(tokens);
    /// }
    /// ```
    pub fn parse(&mut self, tokens: Vec<Token<'text>>) -> Result<(), ParseError<'text>> {
        for token in tokens {
            match token.token_type {
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'text>) -> Result<(), ParseError<'text>> {
        let acceptable = self.current_node
                             .successors()
                             .into_iter()
                             .filter(|n| n.acceptable(self, n))
                             .map(|n| n.clone())
                             .collect::<Vec<_>>();
        let matches = acceptable.clone()
                                .into_iter()
                                .filter(|n| n.matches(self, token))
                                .map(|n| n.clone())
                                .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = &matches[0];
                matching_node.accept(self, token, matching_node);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParseError::NoMatches(token, acceptable)),
            _ => Err(ParseError::AmbiguousMatch(token, matches)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    pub fn verify(&self) -> Result<(), VerifyError> {
        if let Some(&Node::Command(ref command)) = self.commands.first().map(|n| &**n) {
            for expected in &command.parameters {
                if let Node::Parameter(ref param) = **expected {
                    let name = &param.node.name;
                    if param.required && !self.parameters.contains_key(name) {
                        return Err(VerifyError::MissingParameter(name.clone()));
                    }
                } else {
                    unreachable!();
                }
            }
            Ok(())
        } else {
            Err(VerifyError::NoCommandAccepted)
        }
    }
}

/// Errors that calling `parse` on the `Parser` can raise.
#[derive(Clone)]
pub enum ParseError<'text> {
    /// There were no matches for the token.
    NoMatches(Token<'text>, Vec<Rc<Node>>),
    /// There was more than 1 possible match for the token.
    AmbiguousMatch(Token<'text>, Vec<Rc<Node>>),
}

impl<'text> fmt::Debug for ParseError<'text> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::NoMatches(token, _) => write!(f, "NoMatches({:?}, ...)", token),
            ParseError::AmbiguousMatch(token, _) => write!(f, "AmbiguousMatch({:?}, ...)", token),
        }
    }
}

impl<'text> Error for ParseError<'text> {
    fn description(&self) -> &str {
        match *self {
            ParseError::NoMatches(_, _) => "No match.",
            ParseError::AmbiguousMatch(_, _) => "Ambiguous match.",
        }
    }
}

impl<'text> fmt::Display for ParseError<'text> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Errors that calling `verify` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum VerifyError {
    /// No command has been accepted by the parser.
    NoCommandAccepted,
    /// A required parameter is missing.
    MissingParameter(String),
}

impl Error for VerifyError {
    fn description(&self) -> &str {
        match *self {
            VerifyError::NoCommandAccepted => "No command has been accepted by the parser.",
            VerifyError::MissingParameter(_) => "A required parameter is missing.",
        }
    }
}

impl fmt::Display for VerifyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

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

    #[test]
    #[should_panic]
    fn verify_signals_no_command() {
        let root = CommandTree::new().finalize();
        let parser = Parser::new(root);
        match parser.verify() {
            Err(VerifyError::NoCommandAccepted) => panic!(),
            _ => {}
        }
    }

    #[test]
    #[should_panic]
    fn parse_signals_no_matches() {
        let mut tree = CommandTree::new();
        tree.command(Command::new("show"));
        let mut parser = Parser::new(tree.finalize());
        if let Ok(tokens) = tokenize("h") {
            match parser.parse(tokens) {
                Err(ParseError::NoMatches(_, _)) => panic!(),
                _ => {}
            }
        }
    }

    #[test]
    #[should_panic]
    fn parse_signals_ambiguous_match() {
        let mut tree = CommandTree::new();
        tree.command(Command::new("show"));
        tree.command(Command::new("set"));
        let mut parser = Parser::new(tree.finalize());
        if let Ok(tokens) = tokenize("s") {
            match parser.parse(tokens) {
                Err(ParseError::AmbiguousMatch(_, _)) => panic!(),
                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::error::Error;

use rotor::{Machine, EventSet, PollOpt, Scope, Response, Time};
use rotor::void::{unreachable, Void};
use rotor::{GenericScope};

use {ActiveStream, Protocol, Stream, ProtocolStop, Transport};
use extensions::{ResponseExt, ScopeExt};

/// Reconnect timeout in milliseconds.
///
/// TODO(tailhook) should be overridable at runtime
pub const RECONNECT_TIMEOUT: u64 = 200;

/// Time for establishing a connection
///
/// TODO(tailhook) should be overridable at runtime
pub const CONNECT_TIMEOUT: u64 = 1_000;

/// Persistent client connection
///
/// TODO(tailhook) this should include name resolution
pub struct Persistent
(
::Address,
                         P::Seed, Fsm
)
    where P: Protocol, P::Socket: ActiveStream;

#[derive(Debug)]
pub enum Fsm
 {
    Idle,
    Connecting(P::Socket, Time),
    Established(Stream
),
    Sleeping(Time),
}

fn response
(addr:
::Address,
    seed: P::Seed, fsm: Fsm
)
    -> Response<Persistent
, Void>
    where P: Protocol, P::Socket: ActiveStream
{
    use self::Fsm::*;
    let timeo = match *&fsm {
        Idle => None,
        Connecting(_, tm) => Some(tm),
        // Can't find out a timeout for established connection
        // some other way should be used for this case
        Established(..) => unreachable!(),
        Sleeping(tm) => Some(tm),
    };
    println!("Deadline {:?}", timeo);
    Response::ok(Persistent(addr, seed, fsm))
        .deadline_opt(timeo)
}

impl
 Persistent

    where P: Protocol,
          P::Socket: ActiveStream,

::Address: Debug
{
    pub fn new<S: GenericScope>(_scope: &mut S,
            address:
::Address, seed: P::Seed)
        -> Response<Persistent
, Void>
    {
        Response::ok(Persistent(address, seed, Fsm::Idle))
    }

    pub fn connect<S: GenericScope>(scope: &mut S,
            address:
::Address, seed: P::Seed)
        -> Response<Persistent
, Void>
    {
        let fsm = match P::Socket::connect(&address) {
            Ok(sock) => {
                scope.register(&sock, EventSet::writable(), PollOpt::level())
                    .expect("Can't register socket");
                Fsm::Connecting(sock, scope.after(CONNECT_TIMEOUT))
            }
            Err(e) => {
                info!("Failed to connect to {:?}: {}", address, e);
                Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
            }
        };
        response(address, seed, fsm)
    }
    /// Get a `Transport` object of the underlying stream
    ///
    /// This method is only useful if you want to manipulate buffers
    /// externally (like pushing to the buffer from another thread). Just be
    /// sure to **wake up** state machine after manipulating buffers.
    ///
    /// Returns `None` if stream is not currently connected
    pub fn transport(&mut self) -> Option<Transport
> {
        match self.2 {
            Fsm::Established(ref mut s) => Some(s.transport()),
            _ => None,
        }
    }
}

impl
 Fsm

    where P: Protocol,
          P::Seed: Clone,
          P::Socket: ActiveStream,

::Address: Debug
{
    fn action<S: GenericScope>(resp: Response<Stream
, Void>,
        addr:
::Address,
        seed: P::Seed, scope: &mut S)
        -> Response<Persistent
, Void>
    {
        if resp.is_stopped() {
            if let Some(err) = resp.cause() {
                warn!("Connection is failed: {}", err);
            } else {
                warn!("Connection is stopped by protocol");
            }
            response(addr, seed,
                Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT)))
        } else {
            resp
                .wrap(Fsm::Established)
                .wrap(|x| Persistent(addr, seed, x))
        }
    }
}

impl
 Machine for Persistent

    where P: Protocol,
          P::Seed: Clone,
          P::Socket: ActiveStream,

::Address: Debug
{
    type Context = P::Context;
    type Seed = Void;
    fn create(seed: Self::Seed, _scope: &mut Scope
)
        -> Response<Self, Void>
    {
        unreachable(seed)
    }
    fn ready(self, events: EventSet, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Idle => Idle,  // spurious event
            Connecting(sock, dline) => {
                if events.is_writable() {
                    let resp =  Stream::connected(sock, seed.clone(), scope);
                    if resp.is_stopped() {
                        error!("Error creating stream FSM: {}",
                            resp.cause().unwrap_or(&ProtocolStop));
                        Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                    } else {
                        return resp
                            .wrap(Established)
                            .wrap(|x| Persistent(addr, seed, x))
                    }
                } else if events.is_hup() {
                    error!("Connection closed immediately");
                    Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                } else {
                    Connecting(sock, dline) // spurious event
                }
            }
            Established(x) => {
                return Fsm::action(x.ready(events, scope), addr, seed, scope);
            }
            Sleeping(dline) => Sleeping(dline), // spurious event
        };
        response(addr, seed, state)
    }
    fn spawned(self, _scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Idle => Idle,  // spurious timeout
            Connecting(sock, dline) => {
                if scope.now() >= dline {
                    warn!("Timeout while establishing connection");
                    Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                } else {  // spurious timeout
                    Connecting(sock, dline)
                }
            }
            Established(x) => {
                return Fsm::action(x.timeout(scope), addr, seed, scope);
            }
            Sleeping(dline) => {
                if scope.now() >= dline {
                    return Self::connect(scope, addr, seed);
                } else {
                    Sleeping(dline)  // spurious timeout
                }
            }
        };
        response(addr, seed, state)
    }
    fn wakeup(self, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Established(x) => {
                return Fsm::action(x.wakeup(scope), addr, seed, scope);
            }
            x => x, // spurious wakeup
        };
        response(addr, seed, state)
    }
}
<commit_msg>No need for `Debug` of `Address` to get a `Transport`<commit_after>use std::fmt::Debug;
use std::error::Error;

use rotor::{Machine, EventSet, PollOpt, Scope, Response, Time};
use rotor::void::{unreachable, Void};
use rotor::{GenericScope};

use {ActiveStream, Protocol, Stream, ProtocolStop, Transport};
use extensions::{ResponseExt, ScopeExt};

/// Reconnect timeout in milliseconds.
///
/// TODO(tailhook) should be overridable at runtime
pub const RECONNECT_TIMEOUT: u64 = 200;

/// Time for establishing a connection
///
/// TODO(tailhook) should be overridable at runtime
pub const CONNECT_TIMEOUT: u64 = 1_000;

/// Persistent client connection
///
/// TODO(tailhook) this should include name resolution
pub struct Persistent
(
::Address,
                         P::Seed, Fsm
)
    where P: Protocol, P::Socket: ActiveStream;

#[derive(Debug)]
pub enum Fsm
 {
    Idle,
    Connecting(P::Socket, Time),
    Established(Stream
),
    Sleeping(Time),
}

fn response
(addr:
::Address,
    seed: P::Seed, fsm: Fsm
)
    -> Response<Persistent
, Void>
    where P: Protocol, P::Socket: ActiveStream
{
    use self::Fsm::*;
    let timeo = match *&fsm {
        Idle => None,
        Connecting(_, tm) => Some(tm),
        // Can't find out a timeout for established connection
        // some other way should be used for this case
        Established(..) => unreachable!(),
        Sleeping(tm) => Some(tm),
    };
    println!("Deadline {:?}", timeo);
    Response::ok(Persistent(addr, seed, fsm))
        .deadline_opt(timeo)
}

impl
 Persistent

    where P: Protocol,
          P::Socket: ActiveStream,

::Address: Debug
{
    pub fn new<S: GenericScope>(_scope: &mut S,
            address:
::Address, seed: P::Seed)
        -> Response<Persistent
, Void>
    {
        Response::ok(Persistent(address, seed, Fsm::Idle))
    }

    pub fn connect<S: GenericScope>(scope: &mut S,
            address:
::Address, seed: P::Seed)
        -> Response<Persistent
, Void>
    {
        let fsm = match P::Socket::connect(&address) {
            Ok(sock) => {
                scope.register(&sock, EventSet::writable(), PollOpt::level())
                    .expect("Can't register socket");
                Fsm::Connecting(sock, scope.after(CONNECT_TIMEOUT))
            }
            Err(e) => {
                info!("Failed to connect to {:?}: {}", address, e);
                Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
            }
        };
        response(address, seed, fsm)
    }
}

impl
 Persistent

    where P: Protocol, P::Socket: ActiveStream
{
    /// Get a `Transport` object of the underlying stream
    ///
    /// This method is only useful if you want to manipulate buffers
    /// externally (like pushing to the buffer from another thread). Just be
    /// sure to **wake up** state machine after manipulating buffers.
    ///
    /// Returns `None` if stream is not currently connected
    pub fn transport(&mut self) -> Option<Transport
> {
        match self.2 {
            Fsm::Established(ref mut s) => Some(s.transport()),
            _ => None,
        }
    }
}

impl
 Fsm

    where P: Protocol,
          P::Seed: Clone,
          P::Socket: ActiveStream,

::Address: Debug
{
    fn action<S: GenericScope>(resp: Response<Stream
, Void>,
        addr:
::Address,
        seed: P::Seed, scope: &mut S)
        -> Response<Persistent
, Void>
    {
        if resp.is_stopped() {
            if let Some(err) = resp.cause() {
                warn!("Connection is failed: {}", err);
            } else {
                warn!("Connection is stopped by protocol");
            }
            response(addr, seed,
                Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT)))
        } else {
            resp
                .wrap(Fsm::Established)
                .wrap(|x| Persistent(addr, seed, x))
        }
    }
}

impl
 Machine for Persistent

    where P: Protocol,
          P::Seed: Clone,
          P::Socket: ActiveStream,

::Address: Debug
{
    type Context = P::Context;
    type Seed = Void;
    fn create(seed: Self::Seed, _scope: &mut Scope
)
        -> Response<Self, Void>
    {
        unreachable(seed)
    }
    fn ready(self, events: EventSet, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Idle => Idle,  // spurious event
            Connecting(sock, dline) => {
                if events.is_writable() {
                    let resp =  Stream::connected(sock, seed.clone(), scope);
                    if resp.is_stopped() {
                        error!("Error creating stream FSM: {}",
                            resp.cause().unwrap_or(&ProtocolStop));
                        Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                    } else {
                        return resp
                            .wrap(Established)
                            .wrap(|x| Persistent(addr, seed, x))
                    }
                } else if events.is_hup() {
                    error!("Connection closed immediately");
                    Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                } else {
                    Connecting(sock, dline) // spurious event
                }
            }
            Established(x) => {
                return Fsm::action(x.ready(events, scope), addr, seed, scope);
            }
            Sleeping(dline) => Sleeping(dline), // spurious event
        };
        response(addr, seed, state)
    }
    fn spawned(self, _scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Idle => Idle,  // spurious timeout
            Connecting(sock, dline) => {
                if scope.now() >= dline {
                    warn!("Timeout while establishing connection");
                    Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
                } else {  // spurious timeout
                    Connecting(sock, dline)
                }
            }
            Established(x) => {
                return Fsm::action(x.timeout(scope), addr, seed, scope);
            }
            Sleeping(dline) => {
                if scope.now() >= dline {
                    return Self::connect(scope, addr, seed);
                } else {
                    Sleeping(dline)  // spurious timeout
                }
            }
        };
        response(addr, seed, state)
    }
    fn wakeup(self, scope: &mut Scope
)
        -> Response<Self, Self::Seed>
    {
        use self::Fsm::*;
        let Persistent(addr, seed, state) = self;
        let state = match state {
            Established(x) => {
                return Fsm::action(x.wakeup(scope), addr, seed, scope);
            }
            x => x, // spurious wakeup
        };
        response(addr, seed, state)
    }
}
<|endoftext|>


<commit_before>//! Represents JavaScript exceptions as a Rust `Result` type.

use context::Context;
use handle::Handle;
use std::fmt::{Display, Formatter, Result as FmtResult};
use types::Value;

/// An error sentinel type used by `NeonResult` (and `JsResult`) to indicate that the JavaScript engine
/// has entered into a throwing state.
///
/// `Throw` deliberately does not implement `std::error::Error`, because it's generally not a good idea
/// to chain JavaScript exceptions with other kinds of Rust errors, since entering into the throwing
/// state means that the JavaScript engine is unavailable until the exception is handled.
#[derive(Debug)]
pub struct Throw;

impl Display for Throw {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        fmt.write_str("JavaScript Error")
    }
}

/// The result of a computation that might send the JS engine into a throwing state.
pub type NeonResult<T> = Result<T, Throw>;

/// The result of a computation that produces a JavaScript value and might send the JS engine into a throwing state.
pub type JsResult<'b, T> = NeonResult<Handle<'b, T>>;

/// An extension trait for `Result` values that can be converted into `JsResult` values by throwing a JavaScript
/// exception in the error case.
pub trait JsResultExt<'a, V: Value> {
    fn or_throw<'b, C: Context<'b>>(self, cx: &mut C) -> JsResult<'a, V>;
}
<commit_msg>Top-level module API docs for `neon::result`.<commit_after>//! Represents JavaScript exceptions as a Rust [`Result`](std::result) type.
//!
//! Most interactions with the JavaScript engine can throw a JavaScript exception. Neon APIs
//! that can throw an exception are called _throwing APIs_ and return the type
//! [`NeonResult`](NeonResult) (or its shorthand [`JsResult`](JsResult)).
//!
//! When a throwing API triggers a JavaScript exception, it returns an [Err](std::result::Result::Err)
//! result. This indicates that the thread is now throwing, and allows Rust code to perform any
//! cleanup—with an important restriction: **while the JavaScript thread is still throwing,
//! you cannot call additional throwing APIs**. All throwing APIs immediately panic if called
//! while the thread is already throwing.
//!
//! ## Example
//!
//! Neon functions typically use [`JsResult`](JsResult) for their return type. This
//! example defines a function that extracts a property called `"message"` from an object,
//! throwing an exception if the argument is not of the right type or extracting the property
//! fails:
//!
//! ```ignore
//! fn get_message(mut cx: FunctionContext) -> JsResult<JsValue> {
//!     let obj: Handle<JsObject> = cx.argument(0)?;
//!     let prop: Handle<JsValue> = obj.get(&mut cx, "message")?;
//!     Ok(prop)
//! }
//! ```

use context::Context;
use handle::Handle;
use std::fmt::{Display, Formatter, Result as FmtResult};
use types::Value;

/// A [unit type][unit] indicating that the JavaScript thread is throwing an exception.
///
/// `Throw` deliberately does not implement [`std::error::Error`](std::error::Error). It's
/// not recommended to chain JavaScript exceptions with other kinds of Rust errors,
/// since throwing means that the JavaScript thread is unavailable until the exception
/// is handled.
///
/// [unit]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields
#[derive(Debug)]
pub struct Throw;

impl Display for Throw {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        fmt.write_str("JavaScript Error")
    }
}

/// The result type for throwing APIs.
pub type NeonResult<T> = Result<T, Throw>;

/// A result type for throwing APIs that produce JavaScript values.
pub type JsResult<'b, T> = NeonResult<Handle<'b, T>>;

/// Extension trait for converting Rust [`Result`](std::result::Result) values
/// into [`JsResult`](JsResult) values by throwing JavaScript exceptions.
pub trait JsResultExt<'a, V: Value> {
    fn or_throw<'b, C: Context<'b>>(self, cx: &mut C) -> JsResult<'a, V>;
}
<|endoftext|>


<commit_before>//! # Schemes
//! A scheme is a primitive for handling filesystem syscalls in Redox.
//! Schemes accept paths from the kernel for `open`, and file descriptors that they generate
//! are then passed for operations like `close`, `read`, `write`, etc.
//!
//! The kernel validates paths and file descriptors before they are passed to schemes,
//! also stripping the scheme identifier of paths if necessary.

use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::BTreeMap;
use core::sync::atomic::AtomicUsize;
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

use syscall::error::*;
use syscall::scheme::Scheme;

use self::debug::DebugScheme;
use self::event::EventScheme;
use self::env::EnvScheme;
use self::initfs::InitFsScheme;
use self::irq::IrqScheme;
use self::memory::MemoryScheme;
use self::null::NullScheme;
use self::pipe::PipeScheme;
use self::root::RootScheme;
use self::sys::SysScheme;
use self::zero::ZeroScheme;

/// `debug:` - provides access to serial console
pub mod debug;

/// `event:` - allows reading of `Event`s which are registered using `fevent`
pub mod event;

/// `env:` - access and modify environmental variables
pub mod env;

/// `initfs:` - a readonly filesystem used for initializing the system
pub mod initfs;

/// `irq:` - allows userspace handling of IRQs
pub mod irq;

/// When compiled with "live" feature - `disk:` - embedded filesystem for live disk
#[cfg(feature="live")]
pub mod live;

/// `memory:` - a scheme for accessing physical memory
pub mod memory;

/// `null:` - a scheme that will discard all writes, and read no bytes
pub mod null;

/// `pipe:` - used internally by the kernel to implement `pipe`
pub mod pipe;

/// `:` - allows the creation of userspace schemes, tightly dependent on `user`
pub mod root;

/// `sys:` - system information, such as the context list and scheme list
pub mod sys;

/// A wrapper around userspace schemes, tightly dependent on `root`
pub mod user;

/// `zero:` - a scheme that will discard all writes, and always fill read buffers with zero
pub mod zero;

/// Limit on number of schemes
pub const SCHEME_MAX_SCHEMES: usize = 65536;

/// Unique identifier for a scheme namespace.
int_like!(SchemeNamespace, AtomicSchemeNamespace, usize, AtomicUsize);

/// Unique identifier for a scheme.
int_like!(SchemeId, AtomicSchemeId, usize, AtomicUsize);

pub const ATOMIC_SCHEMEID_INIT: AtomicSchemeId = AtomicSchemeId::default();

/// Unique identifier for a file descriptor.
int_like!(FileHandle, AtomicFileHandle, usize, AtomicUsize);

/// Scheme list type
pub struct SchemeList {
    map: BTreeMap<SchemeId, Arc<Box<Scheme + Send + Sync>>>,
    names: BTreeMap<SchemeNamespace, BTreeMap<Box<[u8]>, SchemeId>>,
    next_ns: usize,
    next_id: usize
}

impl SchemeList {
    /// Create a new scheme list.
    pub fn new() -> Self {
        let mut list = SchemeList {
            map: BTreeMap::new(),
            names: BTreeMap::new(),
            next_ns: 0,
            next_id: 1
        };
        list.new_root();
        list
    }

    /// Initialize a new namespace
    fn new_ns(&mut self) -> SchemeNamespace {
        let ns = SchemeNamespace(self.next_ns);
        self.next_ns += 1;
        self.names.insert(ns, BTreeMap::new());

        self.insert(ns, Box::new(*b""), |scheme_id| Arc::new(Box::new(RootScheme::new(ns, scheme_id)))).unwrap();
        self.insert(ns, Box::new(*b"event"), |_| Arc::new(Box::new(EventScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"env"), |_| Arc::new(Box::new(EnvScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"null"), |_| Arc::new(Box::new(NullScheme))).unwrap();
        self.insert(ns, Box::new(*b"sys"), |_| Arc::new(Box::new(SysScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"zero"), |_| Arc::new(Box::new(ZeroScheme))).unwrap();

        ns
    }

    /// Initialize the root namespace
    #[cfg(not(feature="live"))]
    fn new_root(&mut self) {
        // Do common namespace initialization
        let ns = self.new_ns();

        // Debug, Initfs and IRQ are only available in the root namespace. Pipe is special
        self.insert(ns, Box::new(*b"debug"), |scheme_id| Arc::new(Box::new(DebugScheme::new(scheme_id)))).unwrap();
        self.insert(ns, Box::new(*b"initfs"), |_| Arc::new(Box::new(InitFsScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"irq"), |scheme_id| Arc::new(Box::new(IrqScheme::new(scheme_id)))).unwrap();
        self.insert(ns, Box::new(*b"memory"), |_| Arc::new(Box::new(MemoryScheme))).unwrap();
        self.insert(ns, Box::new(*b"pipe"), |scheme_id| Arc::new(Box::new(PipeScheme::new(scheme_id)))).unwrap();
    }

    /// Initialize the root namespace - with live disk
    #[cfg(feature="live")]
    fn new_root(&mut self) {
        // Do common namespace initialization
        let ns = self.new_ns();

        // Debug, Disk, Initfs and IRQ are only available in the root namespace. Pipe is special
        self.insert(ns, Box::new(*b"debug"), |scheme_id| Arc::new(Box::new(DebugScheme::new(scheme_id)))).unwrap();
        self.insert(ns, Box::new(*b"disk"), |_| Arc::new(Box::new(self::live::DiskScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"initfs"), |_| Arc::new(Box::new(InitFsScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"irq"), |scheme_id| Arc::new(Box::new(IrqScheme::new(scheme_id)))).unwrap();
        self.insert(ns, Box::new(*b"memory"), |_| Arc::new(Box::new(MemoryScheme))).unwrap();
        self.insert(ns, Box::new(*b"pipe"), |scheme_id| Arc::new(Box::new(PipeScheme::new(scheme_id)))).unwrap();
    }

    pub fn make_ns(&mut self, from: SchemeNamespace, names: &[&[u8]]) -> Result<SchemeNamespace> {
        // Create an empty namespace
        let to = self.new_ns();

        // Copy requested scheme IDs
        for name in names.iter() {
            let id = if let Some((id, _scheme)) = self.get_name(from, name) {
                id
            } else {
                return Err(Error::new(ENODEV));
            };

            if let Some(ref mut names) = self.names.get_mut(&to) {
                assert!(names.insert(name.to_vec().into_boxed_slice(), id).is_none());
            } else {
                panic!("scheme namespace not found");
            }
        }

        Ok(to)
    }

    pub fn iter(&self) -> ::collections::btree_map::Iter<SchemeId, Arc<Box<Scheme + Send + Sync>>> {
        self.map.iter()
    }

    pub fn iter_name(&self, ns: SchemeNamespace) -> ::collections::btree_map::Iter<Box<[u8]>, SchemeId> {
        self.names[&ns].iter()
    }

    /// Get the nth scheme.
    pub fn get(&self, id: SchemeId) -> Option<&Arc<Box<Scheme + Send + Sync>>> {
        self.map.get(&id)
    }

    pub fn get_name(&self, ns: SchemeNamespace, name: &[u8]) -> Option<(SchemeId, &Arc<Box<Scheme + Send + Sync>>)> {
        if let Some(&id) = self.names[&ns].get(name) {
            self.get(id).map(|scheme| (id, scheme))
        } else {
            None
        }
    }

    /// Create a new scheme.
    pub fn insert<F>(&mut self, ns: SchemeNamespace, name: Box<[u8]>, scheme_fn: F) -> Result<SchemeId>
        where F: Fn(SchemeId) -> Arc<Box<Scheme + Send + Sync>>
    {
        if self.names[&ns].contains_key(&name) {
            return Err(Error::new(EEXIST));
        }

        if self.next_id >= SCHEME_MAX_SCHEMES {
            self.next_id = 1;
        }

        while self.map.contains_key(&SchemeId(self.next_id)) {
            self.next_id += 1;
        }

        /* Allow scheme list to grow if required
        if self.next_id >= SCHEME_MAX_SCHEMES {
            return Err(Error::new(EAGAIN));
        }
        */

        let id = SchemeId(self.next_id);
        self.next_id += 1;

        let scheme = scheme_fn(id);

        assert!(self.map.insert(id, scheme).is_none());
        if let Some(ref mut names) = self.names.get_mut(&ns) {
            assert!(names.insert(name, id).is_none());
        } else {
            panic!("scheme namespace not found");
        }
        Ok(id)
    }
}

/// Schemes list
static SCHEMES: Once<RwLock<SchemeList>> = Once::new();

/// Initialize schemes, called if needed
fn init_schemes() -> RwLock<SchemeList> {
    RwLock::new(SchemeList::new())
}

/// Get the global schemes list, const
pub fn schemes() -> RwLockReadGuard<'static, SchemeList> {
    SCHEMES.call_once(init_schemes).read()
}

/// Get the global schemes list, mutable
pub fn schemes_mut() -> RwLockWriteGuard<'static, SchemeList> {
    SCHEMES.call_once(init_schemes).write()
}
<commit_msg>Allow memory: to be accessed in all namespaces<commit_after>//! # Schemes
//! A scheme is a primitive for handling filesystem syscalls in Redox.
//! Schemes accept paths from the kernel for `open`, and file descriptors that they generate
//! are then passed for operations like `close`, `read`, `write`, etc.
//!
//! The kernel validates paths and file descriptors before they are passed to schemes,
//! also stripping the scheme identifier of paths if necessary.

use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::BTreeMap;
use core::sync::atomic::AtomicUsize;
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

use syscall::error::*;
use syscall::scheme::Scheme;

use self::debug::DebugScheme;
use self::event::EventScheme;
use self::env::EnvScheme;
use self::initfs::InitFsScheme;
use self::irq::IrqScheme;
use self::memory::MemoryScheme;
use self::null::NullScheme;
use self::pipe::PipeScheme;
use self::root::RootScheme;
use self::sys::SysScheme;
use self::zero::ZeroScheme;

/// `debug:` - provides access to serial console
pub mod debug;

/// `event:` - allows reading of `Event`s which are registered using `fevent`
pub mod event;

/// `env:` - access and modify environmental variables
pub mod env;

/// `initfs:` - a readonly filesystem used for initializing the system
pub mod initfs;

/// `irq:` - allows userspace handling of IRQs
pub mod irq;

/// When compiled with "live" feature - `disk:` - embedded filesystem for live disk
#[cfg(feature="live")]
pub mod live;

/// `memory:` - a scheme for accessing physical memory
pub mod memory;

/// `null:` - a scheme that will discard all writes, and read no bytes
pub mod null;

/// `pipe:` - used internally by the kernel to implement `pipe`
pub mod pipe;

/// `:` - allows the creation of userspace schemes, tightly dependent on `user`
pub mod root;

/// `sys:` - system information, such as the context list and scheme list
pub mod sys;

/// A wrapper around userspace schemes, tightly dependent on `root`
pub mod user;

/// `zero:` - a scheme that will discard all writes, and always fill read buffers with zero
pub mod zero;

/// Limit on number of schemes
pub const SCHEME_MAX_SCHEMES: usize = 65536;

/// Unique identifier for a scheme namespace.
int_like!(SchemeNamespace, AtomicSchemeNamespace, usize, AtomicUsize);

/// Unique identifier for a scheme.
int_like!(SchemeId, AtomicSchemeId, usize, AtomicUsize);

pub const ATOMIC_SCHEMEID_INIT: AtomicSchemeId = AtomicSchemeId::default();

/// Unique identifier for a file descriptor.
int_like!(FileHandle, AtomicFileHandle, usize, AtomicUsize);

/// Scheme list type
pub struct SchemeList {
    map: BTreeMap<SchemeId, Arc<Box<Scheme + Send + Sync>>>,
    names: BTreeMap<SchemeNamespace, BTreeMap<Box<[u8]>, SchemeId>>,
    next_ns: usize,
    next_id: usize
}

impl SchemeList {
    /// Create a new scheme list.
    pub fn new() -> Self {
        let mut list = SchemeList {
            map: BTreeMap::new(),
            names: BTreeMap::new(),
            next_ns: 0,
            next_id: 1
        };
        list.new_root();
        list
    }

    /// Initialize a new namespace
    fn new_ns(&mut self) -> SchemeNamespace {
        let ns = SchemeNamespace(self.next_ns);
        self.next_ns += 1;
        self.names.insert(ns, BTreeMap::new());

        self.insert(ns, Box::new(*b""), |scheme_id| Arc::new(Box::new(RootScheme::new(ns, scheme_id)))).unwrap();
        self.insert(ns, Box::new(*b"event"), |_| Arc::new(Box::new(EventScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"env"), |_| Arc::new(Box::new(EnvScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"memory"), |_| Arc::new(Box::new(MemoryScheme))).unwrap();
        self.insert(ns, Box::new(*b"null"), |_| Arc::new(Box::new(NullScheme))).unwrap();
        self.insert(ns, Box::new(*b"sys"), |_| Arc::new(Box::new(SysScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"zero"), |_| Arc::new(Box::new(ZeroScheme))).unwrap();

        ns
    }

    /// Initialize the root namespace
    #[cfg(not(feature="live"))]
    fn new_root(&mut self) {
        // Do common namespace initialization
        let ns = self.new_ns();

        // Debug, Initfs and IRQ are only available in the root namespace. Pipe is special
        self.insert(ns, Box::new(*b"debug"), |scheme_id| Arc::new(Box::new(DebugScheme::new(scheme_id)))).unwrap();
        self.insert(ns, Box::new(*b"initfs"), |_| Arc::new(Box::new(InitFsScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"irq"), |scheme_id| Arc::new(Box::new(IrqScheme::new(scheme_id)))).unwrap();
        self.insert(ns, Box::new(*b"pipe"), |scheme_id| Arc::new(Box::new(PipeScheme::new(scheme_id)))).unwrap();
    }

    /// Initialize the root namespace - with live disk
    #[cfg(feature="live")]
    fn new_root(&mut self) {
        // Do common namespace initialization
        let ns = self.new_ns();

        // Debug, Disk, Initfs and IRQ are only available in the root namespace. Pipe is special
        self.insert(ns, Box::new(*b"debug"), |scheme_id| Arc::new(Box::new(DebugScheme::new(scheme_id)))).unwrap();
        self.insert(ns, Box::new(*b"disk"), |_| Arc::new(Box::new(self::live::DiskScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"initfs"), |_| Arc::new(Box::new(InitFsScheme::new()))).unwrap();
        self.insert(ns, Box::new(*b"irq"), |scheme_id| Arc::new(Box::new(IrqScheme::new(scheme_id)))).unwrap();
        self.insert(ns, Box::new(*b"pipe"), |scheme_id| Arc::new(Box::new(PipeScheme::new(scheme_id)))).unwrap();
    }

    pub fn make_ns(&mut self, from: SchemeNamespace, names: &[&[u8]]) -> Result<SchemeNamespace> {
        // Create an empty namespace
        let to = self.new_ns();

        // Copy requested scheme IDs
        for name in names.iter() {
            let id = if let Some((id, _scheme)) = self.get_name(from, name) {
                id
            } else {
                return Err(Error::new(ENODEV));
            };

            if let Some(ref mut names) = self.names.get_mut(&to) {
                assert!(names.insert(name.to_vec().into_boxed_slice(), id).is_none());
            } else {
                panic!("scheme namespace not found");
            }
        }

        Ok(to)
    }

    pub fn iter(&self) -> ::collections::btree_map::Iter<SchemeId, Arc<Box<Scheme + Send + Sync>>> {
        self.map.iter()
    }

    pub fn iter_name(&self, ns: SchemeNamespace) -> ::collections::btree_map::Iter<Box<[u8]>, SchemeId> {
        self.names[&ns].iter()
    }

    /// Get the nth scheme.
    pub fn get(&self, id: SchemeId) -> Option<&Arc<Box<Scheme + Send + Sync>>> {
        self.map.get(&id)
    }

    pub fn get_name(&self, ns: SchemeNamespace, name: &[u8]) -> Option<(SchemeId, &Arc<Box<Scheme + Send + Sync>>)> {
        if let Some(&id) = self.names[&ns].get(name) {
            self.get(id).map(|scheme| (id, scheme))
        } else {
            None
        }
    }

    /// Create a new scheme.
    pub fn insert<F>(&mut self, ns: SchemeNamespace, name: Box<[u8]>, scheme_fn: F) -> Result<SchemeId>
        where F: Fn(SchemeId) -> Arc<Box<Scheme + Send + Sync>>
    {
        if self.names[&ns].contains_key(&name) {
            return Err(Error::new(EEXIST));
        }

        if self.next_id >= SCHEME_MAX_SCHEMES {
            self.next_id = 1;
        }

        while self.map.contains_key(&SchemeId(self.next_id)) {
            self.next_id += 1;
        }

        /* Allow scheme list to grow if required
        if self.next_id >= SCHEME_MAX_SCHEMES {
            return Err(Error::new(EAGAIN));
        }
        */

        let id = SchemeId(self.next_id);
        self.next_id += 1;

        let scheme = scheme_fn(id);

        assert!(self.map.insert(id, scheme).is_none());
        if let Some(ref mut names) = self.names.get_mut(&ns) {
            assert!(names.insert(name, id).is_none());
        } else {
            panic!("scheme namespace not found");
        }
        Ok(id)
    }
}

/// Schemes list
static SCHEMES: Once<RwLock<SchemeList>> = Once::new();

/// Initialize schemes, called if needed
fn init_schemes() -> RwLock<SchemeList> {
    RwLock::new(SchemeList::new())
}

/// Get the global schemes list, const
pub fn schemes() -> RwLockReadGuard<'static, SchemeList> {
    SCHEMES.call_once(init_schemes).read()
}

/// Get the global schemes list, mutable
pub fn schemes_mut() -> RwLockWriteGuard<'static, SchemeList> {
    SCHEMES.call_once(init_schemes).write()
}
<|endoftext|>


<commit_before>#[crate_id = "sobol#0.1"];
#[comment = "Sobol indices evaluator"];
#[license = "MIT"];

use params::{Params, Value, Float, Range};
use model::{Model,Gompertz};
use std::vec;
use std::hashmap::HashMap;
pub mod model;
pub mod params;

fn sample(pr: &Params, num_real : uint) -> ~[Params] {
    let mut samples : ~[Params] = ~[];
    for _ in range(0, num_real) {
        samples.push(pr.realize());
    }
    samples
}
#[test]
fn test_sample() {
    let mut ranges=Params::new();
    ranges.insert("alpha", Range(0.0, 1.0));
    let samples=sample(&ranges, 10);

    assert_eq!(samples.len(), 10);
    for pp in samples.iter() {
        let value=pp.get_float("alpha");
        assert!((value>=0.0)&&(value<=1.0));
    }
}

#[allow(dead_code)]
fn eval_model(pr: &Params) -> f64 {
    let model : Gompertz = Model::setup(pr);
    model.run()
}

fn get_couples(n : uint) -> ~[(uint, uint)] {
    let mut res : ~[(uint, uint)]=~[];
    for i in range(0, n) {
        for j in range(i, n) {
            if (i!=j) {
                res.push( (i,j));
            }
        }
    }
    res
}

#[test]
fn test_get_couples() {
    let res=get_couples(3);

    assert_eq!(res[0], (0,1));
    assert_eq!(res[1], (0,2));
    assert_eq!(res[2], (1,2));
}

// First order Sobol indices
#[allow(dead_code)]
fn calc_sobol_1(pr: &Params, nsamp : uint) -> HashMap<~str, f64> {
    let samples_1=sample(pr, nsamp);
    let samples_2=sample(pr, nsamp);

    let big_one : ~[Params] = vec::append(samples_1.clone(), samples_2);

    // Average and deviation computaion
    let resvec=big_one.map(eval_model);
    let avg=resvec.iter().fold(0.0, |acc, &item| acc+item)/(resvec.len() as f64);
    let var=resvec.iter().fold(0.0, |acc, &item| acc+item*item)/(resvec.len() as f64)-avg*avg;

    let mut Sp: HashMap<~str, f64> = HashMap::new();
    for (k,_v) in pr.pp.iter() {
        let mut sump=0.0f64;
        for snum in range(0, nsamp) {
            let mut new_p=samples_2[snum].clone();
            new_p.set(k.to_owned(),Float(samples_1[snum].get_float(k.to_owned())));

            sump=sump+eval_model(&new_p)*eval_model(&samples_1[snum]);
        }
        let Up=sump/(nsamp as f64);
        Sp.insert(k.to_owned(), (Up-avg*avg)/var);
    }

    Sp
}

// Second order Sobol indices
#[allow(dead_code)]
fn calc_sobol_2(pr: &Params, sob1 : &HashMap<~str, f64>, nsamp : uint) -> ~[(~str, ~str, f64)] {
    let samples_1=sample(pr, nsamp);
    let samples_2=sample(pr, nsamp);
    let couples=get_couples(pr.len());

    let big_one : ~[Params] = vec::append(samples_1.clone(), samples_2);

    // Average and deviation computaion
    let resvec=big_one.map(eval_model);
    let avg=resvec.iter().fold(0.0, |acc, &item| acc+item)/(resvec.len() as f64);
    let var=resvec.iter().fold(0.0, |acc, &item| acc+item*item)/(resvec.len() as f64)-avg*avg;

    let mut Spr : ~[(~str, ~str, f64)]=~[];
    let keys=pr.keys();

    for &cpl in couples.iter() {
        let (i,j) = cpl;
        let ref key1=keys[i]; let ref key2=keys[j];
        let mut sump=0.0f64;
        for snum in range(0, nsamp) {
            let mut new_p=samples_2[snum].clone();
            new_p.set(key1.to_owned(),Float(samples_1[snum].get_float(key1.to_owned())));
            new_p.set(key2.to_owned(),Float(samples_1[snum].get_float(key2.to_owned())));

            sump=sump+eval_model(&new_p)*eval_model(&samples_1[snum]);
        }
        let Upr=sump/(nsamp as f64);
        let Vp=*sob1.find_equiv(key1).unwrap();
        let Vr=*sob1.find_equiv(key2).unwrap();
        Spr.push((key1.to_owned(), key2.to_owned(), (Upr-avg*avg-Vr-Vp)/var));
    }

    Spr
}

//
// Entry point
//
#[allow(dead_code)]
fn main() {
  let mut ranges=Params::new();
  ranges.insert("alpha", Range(0.01, 1.0)); ranges.insert("K", Range(0.01, 1.0)); ranges.insert("C0", Range(0.001, 0.01));

  let samples=sample(&ranges,5000);
  let resvec=samples.map(eval_model);

  let avg=resvec.iter().fold(0.0, |acc, &item| acc+item)/(resvec.len() as f64);
  let var=resvec.iter().fold(0.0, |acc, &item| acc+item*item)/(resvec.len() as f64)-avg*avg;

  println!("Mean value = {}, Standard Deviation = {}\n", avg, var);
  let sob_1=calc_sobol_1(&ranges,15000);
  println!("First order Sobol indices");
  for (k, v) in sob_1.iter() {
    println!("\t{:s} = {:f}", *k, *v);
  }
  let sob_2=calc_sobol_2(&ranges, &sob_1, 7500);
  println!("\nSecond order Sobol indices");
  for vv in sob_2.iter() {
    let (ref k1,ref k2,v) = *vv;
    println!("\t{:s} x {:s} = {:f}", *k1, *k2, v);
  }
}

<commit_msg>Compute Total Sobol indices<commit_after>#[crate_id = "sobol#0.1"];
#[comment = "Sobol indices evaluator"];
#[license = "MIT"];

use params::{Params, Value, Float, Range};
use model::{Model,Gompertz};
use std::vec;
use std::hashmap::HashMap;
pub mod model;
pub mod params;

fn sample(pr: &Params, num_real : uint) -> ~[Params] {
    let mut samples : ~[Params] = ~[];
    for _ in range(0, num_real) {
        samples.push(pr.realize());
    }
    samples
}
#[test]
fn test_sample() {
    let mut ranges=Params::new();
    ranges.insert("alpha", Range(0.0, 1.0));
    let samples=sample(&ranges, 10);

    assert_eq!(samples.len(), 10);
    for pp in samples.iter() {
        let value=pp.get_float("alpha");
        assert!((value>=0.0)&&(value<=1.0));
    }
}

#[allow(dead_code)]
fn eval_model(pr: &Params) -> f64 {
    let model : Gompertz = Model::setup(pr);
    model.run()
}

fn get_couples(n : uint) -> ~[(uint, uint)] {
    let mut res : ~[(uint, uint)]=~[];
    for i in range(0, n) {
        for j in range(i, n) {
            if (i!=j) {
                res.push( (i,j));
            }
        }
    }
    res
}

#[test]
fn test_get_couples() {
    let res=get_couples(3);

    assert_eq!(res[0], (0,1));
    assert_eq!(res[1], (0,2));
    assert_eq!(res[2], (1,2));
}

// First order Sobol indices
#[allow(dead_code)]
fn calc_sobol_1(pr: &Params, nsamp : uint) -> HashMap<~str, f64> {
    let samples_1=sample(pr, nsamp);
    let samples_2=sample(pr, nsamp);

    let big_one : ~[Params] = vec::append(samples_1.clone(), samples_2);

    // Average and deviation computaion
    let resvec=big_one.map(eval_model);
    let avg=resvec.iter().fold(0.0, |acc, &item| acc+item)/(resvec.len() as f64);
    let var=resvec.iter().fold(0.0, |acc, &item| acc+item*item)/(resvec.len() as f64)-avg*avg;

    let mut Sp: HashMap<~str, f64> = HashMap::new();
    for (k,_v) in pr.pp.iter() {
        let mut sump=0.0f64;
        for snum in range(0, nsamp) {
            let mut new_p=samples_2[snum].clone();
            new_p.set(k.to_owned(),Float(samples_1[snum].get_float(k.to_owned())));

            sump=sump+eval_model(&new_p)*eval_model(&samples_1[snum]);
        }
        let Up=sump/(nsamp as f64);
        Sp.insert(k.to_owned(), (Up-avg*avg)/var);
    }

    Sp
}

// Second order Sobol indices
#[allow(dead_code)]
fn calc_sobol_2(pr: &Params, sob1 : &HashMap<~str, f64>, nsamp : uint) -> ~[(~str, ~str, f64)] {
    let samples_1=sample(pr, nsamp);
    let samples_2=sample(pr, nsamp);
    let couples=get_couples(pr.len());

    let big_one : ~[Params] = vec::append(samples_1.clone(), samples_2);

    // Average and deviation computaion
    let resvec=big_one.map(eval_model);
    let avg=resvec.iter().fold(0.0, |acc, &item| acc+item)/(resvec.len() as f64);
    let var=resvec.iter().fold(0.0, |acc, &item| acc+item*item)/(resvec.len() as f64)-avg*avg;

    let mut Spr : ~[(~str, ~str, f64)]=~[];
    let keys=pr.keys();

    for &cpl in couples.iter() {
        let (i,j) = cpl;
        let ref key1=keys[i]; let ref key2=keys[j];
        let mut sump=0.0f64;
        for snum in range(0, nsamp) {
            let mut new_p=samples_2[snum].clone();
            new_p.set(key1.to_owned(),Float(samples_1[snum].get_float(key1.to_owned())));
            new_p.set(key2.to_owned(),Float(samples_1[snum].get_float(key2.to_owned())));

            sump=sump+eval_model(&new_p)*eval_model(&samples_1[snum]);
        }
        let Upr=sump/(nsamp as f64);
        let Vp=*sob1.find_equiv(key1).unwrap();
        let Vr=*sob1.find_equiv(key2).unwrap();
        Spr.push((key1.to_owned(), key2.to_owned(), (Upr-avg*avg-Vr-Vp)/var));
    }

    Spr
}

// Total Sobol indices
fn calc_sobol_total(pr: &Params, nsamp : uint) -> HashMap<~str, f64> {
    let samples_1=sample(pr, nsamp);
    let samples_2=sample(pr, nsamp);

    let big_one : ~[Params] = vec::append(samples_1.clone(), samples_2);

    // Average and deviation computaion
    let resvec=big_one.map(eval_model);
    let avg=resvec.iter().fold(0.0, |acc, &item| acc+item)/(resvec.len() as f64);
    let var=resvec.iter().fold(0.0, |acc, &item| acc+item*item)/(resvec.len() as f64)-avg*avg;

    let mut Sp: HashMap<~str, f64> = HashMap::new();
    for (k,_v) in pr.pp.iter() {
        let mut sump=0.0f64;
        for snum in range(0, nsamp) {
            let mut new_p=samples_1[snum].clone();
            new_p.set(k.to_owned(),Float(samples_2[snum].get_float(k.slice_from(0))));

            sump=sump+eval_model(&new_p)*eval_model(&samples_1[snum]);
        }
        let Up=sump/(nsamp as f64);
        Sp.insert(k.to_owned(), 1.0-(Up-avg*avg)/var);
    }

    Sp
}

//
// Entry point
//
#[allow(dead_code)]
fn main() {
  let mut ranges=Params::new();
  ranges.insert("alpha", Range(0.01, 1.0)); ranges.insert("K", Range(0.01, 1.0)); ranges.insert("C0", Range(0.001, 0.01));

  let samples=sample(&ranges,5000);
  let resvec=samples.map(eval_model);

  let avg=resvec.iter().fold(0.0, |acc, &item| acc+item)/(resvec.len() as f64);
  let var=resvec.iter().fold(0.0, |acc, &item| acc+item*item)/(resvec.len() as f64)-avg*avg;

  println!("Mean value = {}, Standard Deviation = {}\n", avg, var);

  println!("First order Sobol indices");
  let sob_1=calc_sobol_1(&ranges,15000);
  for (k, v) in sob_1.iter() {
    println!("\t{:s} = {:f}", *k, *v);
  }

  println!("\nSecond order Sobol indices");
  let sob_2=calc_sobol_2(&ranges, &sob_1, 7500);
  for vv in sob_2.iter() {
    let (ref k1,ref k2,v) = *vv;
    println!("\t{:s} x {:s} = {:f}", *k1, *k2, v);
  }

  println!("\nTotal Sobol indices");
  let sob_t=calc_sobol_total(&ranges, 15000);
  for (k, v) in sob_t.iter() {
    println!("\t{:s} = {:f}", *k, *v);
  }

}

<|endoftext|>


<commit_before>//! Asynchronous access to multithreaded computation in a Node plugin.

use std::marker::{Send, Sized};
use std::mem;
use std::os::raw::c_void;

use types::{Value, JsFunction};
use result::JsResult;
use handle::{Handle, Managed};
use context::TaskContext;
use neon_runtime;
use neon_runtime::raw;

/// A Rust task that can be executed in a background thread.
pub trait Task: Send + Sized {
    /// The task's result type, which is sent back to the main thread to communicate a successful result back to JavaScript.
    type Output: Send;

    /// The task's error type, which is sent back to the main thread to communicate a task failure back to JavaScript.
    type Error: Send;

    /// The type of JavaScript value that gets produced to the asynchronous callback on the main thread after the task is completed.
    type JsEvent: Value;

    /// Perform the task, producing either a successful `Output` or an unsuccessful `Error`. This method is executed in a background thread as part of libuv's built-in thread pool.
    fn perform(&self) -> Result<Self::Output, Self::Error>;

    /// Convert the result of the task to a JavaScript value to be passed to the asynchronous callback. This method is executed on the main thread at some point after the background task is completed.
    fn complete<'a>(self, cx: TaskContext<'a>, result: Result<Self::Output, Self::Error>) -> JsResult<Self::JsEvent>;

    /// Schedule a task to be executed on a background thread.
    ///
    /// `callback` should have the following signature:
    ///
    /// ```js
    /// function callback(err, value) {}
    /// ```
    fn schedule(self, callback: Handle<JsFunction>) {
        let boxed_self = Box::new(self);
        let self_raw = Box::into_raw(boxed_self);
        let callback_raw = callback.to_raw();
        unsafe {
            neon_runtime::task::schedule(mem::transmute(self_raw),
                                         perform_task::<Self>,
                                         complete_task::<Self>,
                                         callback_raw);
        }
    }
}

unsafe extern "C" fn perform_task<T: Task>(task: *mut c_void) -> *mut c_void {
    let task: Box<T> = Box::from_raw(mem::transmute(task));
    let result = task.perform();
    Box::into_raw(task);
    mem::transmute(Box::into_raw(Box::new(result)))
}

unsafe extern "C" fn complete_task<T: Task>(task: *mut c_void, result: *mut c_void, out: &mut raw::Local) {
    let result: Result<T::Output, T::Error> = *Box::from_raw(mem::transmute(result));
    let task: Box<T> = Box::from_raw(mem::transmute(task));
    TaskContext::with(|cx| {
        if let Ok(result) = task.complete(cx, result) {
            *out = result.to_raw();
        }
    })
}
<commit_msg>Task trait should be marked 'static. Fixes #288<commit_after>//! Asynchronous access to multithreaded computation in a Node plugin.

use std::marker::{Send, Sized};
use std::mem;
use std::os::raw::c_void;

use types::{Value, JsFunction};
use result::JsResult;
use handle::{Handle, Managed};
use context::TaskContext;
use neon_runtime;
use neon_runtime::raw;

/// A Rust task that can be executed in a background thread.
pub trait Task: Send + Sized + 'static {
    /// The task's result type, which is sent back to the main thread to communicate a successful result back to JavaScript.
    type Output: Send + 'static;

    /// The task's error type, which is sent back to the main thread to communicate a task failure back to JavaScript.
    type Error: Send + 'static;

    /// The type of JavaScript value that gets produced to the asynchronous callback on the main thread after the task is completed.
    type JsEvent: Value;

    /// Perform the task, producing either a successful `Output` or an unsuccessful `Error`. This method is executed in a background thread as part of libuv's built-in thread pool.
    fn perform(&self) -> Result<Self::Output, Self::Error>;

    /// Convert the result of the task to a JavaScript value to be passed to the asynchronous callback. This method is executed on the main thread at some point after the background task is completed.
    fn complete<'a>(self, cx: TaskContext<'a>, result: Result<Self::Output, Self::Error>) -> JsResult<Self::JsEvent>;

    /// Schedule a task to be executed on a background thread.
    ///
    /// `callback` should have the following signature:
    ///
    /// ```js
    /// function callback(err, value) {}
    /// ```
    fn schedule(self, callback: Handle<JsFunction>) {
        let boxed_self = Box::new(self);
        let self_raw = Box::into_raw(boxed_self);
        let callback_raw = callback.to_raw();
        unsafe {
            neon_runtime::task::schedule(mem::transmute(self_raw),
                                         perform_task::<Self>,
                                         complete_task::<Self>,
                                         callback_raw);
        }
    }
}

unsafe extern "C" fn perform_task<T: Task>(task: *mut c_void) -> *mut c_void {
    let task: Box<T> = Box::from_raw(mem::transmute(task));
    let result = task.perform();
    Box::into_raw(task);
    mem::transmute(Box::into_raw(Box::new(result)))
}

unsafe extern "C" fn complete_task<T: Task>(task: *mut c_void, result: *mut c_void, out: &mut raw::Local) {
    let result: Result<T::Output, T::Error> = *Box::from_raw(mem::transmute(result));
    let task: Box<T> = Box::from_raw(mem::transmute(task));
    TaskContext::with(|cx| {
        if let Ok(result) = task.complete(cx, result) {
            *out = result.to_raw();
        }
    })
}
<|endoftext|>


<commit_before>use time;
use time::{Timespec, Tm};
use std::fmt::{Display, Error, Formatter};

/// Trait that allows to display a time into a local or UTC timezone.
pub trait TimeDisplay {
    /// The displayable type
    type D: Display;

    /// Turns self into a displayable type that when displayed uses the local time zone.
    fn into_local_display(self) -> Self::D;
    /// Turns self into a displayable type that when displayed uses the UTC time zone.
    fn into_utc_display(self) -> Self::D;
}

/// Utility struct that implements Display in a pretty style
/// for some Tm instance.
pub struct PrettyDisplay {
    tm: Tm,
}

/// The format to be used to display a time.
/// It could be a local or an UTC time.
#[allow(dead_code)]
pub enum Format {
    Local,
    Utc,
}

/// Parse a string representing a duplicity timestamp and returns a Timespec
/// if all goes well.
pub fn parse_time_str(s: &str) -> Option<Timespec> {
    time::strptime(s, "%Y%m%dt%H%M%S%Z").ok().map(|tm| tm.to_timespec())
}

impl TimeDisplay for Timespec {
    type D = PrettyDisplay;

    fn into_local_display(self) -> Self::D {
        PrettyDisplay { tm: time::at(self) }
    }

    fn into_utc_display(self) -> Self::D {
        PrettyDisplay { tm: time::at_utc(self) }
    }
}

impl Display for PrettyDisplay {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        if time::now_utc().tm_year == self.tm.tm_year {
            // the year is the current, so print month, day, hour
            write!(f, "{}", time::strftime("%b %d %R", &self.tm).unwrap())
        } else {
            // the year is not the current, so print month, day, year
            // NOTE: the double space before year is meaningful
            write!(f, "{}", time::strftime("%b %d  %Y", &self.tm).unwrap())
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::env;
    use time::{self, Tm};

    fn time(y: i32, mon: i32, d: i32, h: i32, min: i32, s: i32) -> Tm {
        Tm {
            tm_sec: s,
            tm_min: min,
            tm_hour: h,
            tm_mday: d,
            tm_mon: mon - 1,
            tm_year: y - 1900,
            tm_wday: 0,
            tm_yday: d,
            tm_isdst: 0,
            tm_utcoff: 0,
            tm_nsec: 0,
        }
    }

    fn this_year() -> i32 {
        time::now_utc().tm_year
    }

    fn move_to_this_year(mut tm: Tm) -> Tm {
        tm.tm_year = this_year();
        tm
    }

    fn set_time_zone(tz: &str) {
        env::set_var("TZ", tz);
        time::tzset();
    }

    #[test]
    fn parse() {
        let time = parse_time_str("19881211t152000z").unwrap();
        let tm = time::at_utc(time);
        assert_eq!(tm.tm_year, 88);
        assert_eq!(tm.tm_mon, 11);  // month in [0 - 11]
        assert_eq!(tm.tm_mday, 11);
        assert_eq!(tm.tm_hour, 15);
        assert_eq!(tm.tm_min, 20);
        assert_eq!(tm.tm_sec, 0);
    }

    #[test]
    fn display_utc() {
        let time = move_to_this_year(time(1988, 12, 11, 15, 20, 0));
        assert_eq!(format!("{}", time.to_timespec().into_utc_display()), "Dec 11 15:20");
    }

    // NOTE: changing the time zone is global in the process,
    //       tests are run in parallel,
    //       so, to avoid race conditions in tests requiring a certain timezone you have two
    //       options:
    //       - put every test in the same `test` function
    //       - use a global mutex
    //       we are now using the first option, since the following is the only test requiring a
    //       certain time zone to be set.
    #[test]
    fn display_local() {
        let time = move_to_this_year(time(1988, 12, 11, 15, 20, 0));
        set_time_zone("Europe/London");
        assert_eq!(format!("{}", time.to_timespec().into_local_display()), "Dec 11 15:20");
        set_time_zone("Europe/Rome");
        assert_eq!(format!("{}", time.to_timespec().into_local_display()), "Dec 11 16:20");
    }

    #[test]
    fn display_past_year() {
        let time = time(1988, 12, 11, 15, 20, 0);
        assert_eq!(format!("{}", time.to_timespec().into_utc_display()), "Dec 11  1988");
    }

    #[test]
    fn parse_display_past_year() {
        let time = parse_time_str("19881211t152000z").unwrap();
        assert_eq!(format!("{}", time.into_utc_display()), "Dec 11  1988");
    }
}
<commit_msg>Use tuple struct for PrettyDisplay<commit_after>use time;
use time::{Timespec, Tm};
use std::fmt::{Display, Error, Formatter};

/// Trait that allows to display a time into a local or UTC timezone.
pub trait TimeDisplay {
    /// The displayable type
    type D: Display;

    /// Turns self into a displayable type that when displayed uses the local time zone.
    fn into_local_display(self) -> Self::D;
    /// Turns self into a displayable type that when displayed uses the UTC time zone.
    fn into_utc_display(self) -> Self::D;
}

/// Utility struct that implements Display in a pretty style
/// for some Tm instance.
pub struct PrettyDisplay(Tm);

/// The format to be used to display a time.
/// It could be a local or an UTC time.
#[allow(dead_code)]
pub enum Format {
    Local,
    Utc,
}

/// Parse a string representing a duplicity timestamp and returns a Timespec
/// if all goes well.
pub fn parse_time_str(s: &str) -> Option<Timespec> {
    time::strptime(s, "%Y%m%dt%H%M%S%Z").ok().map(|tm| tm.to_timespec())
}

impl TimeDisplay for Timespec {
    type D = PrettyDisplay;

    fn into_local_display(self) -> Self::D {
        PrettyDisplay(time::at(self))
    }

    fn into_utc_display(self) -> Self::D {
        PrettyDisplay(time::at_utc(self))
    }
}

impl Display for PrettyDisplay {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        if time::now_utc().tm_year == self.0.tm_year {
            // the year is the current, so print month, day, hour
            write!(f, "{}", time::strftime("%b %d %R", &self.0).unwrap())
        } else {
            // the year is not the current, so print month, day, year
            // NOTE: the double space before year is meaningful
            write!(f, "{}", time::strftime("%b %d  %Y", &self.0).unwrap())
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::env;
    use time::{self, Tm};

    fn time(y: i32, mon: i32, d: i32, h: i32, min: i32, s: i32) -> Tm {
        Tm {
            tm_sec: s,
            tm_min: min,
            tm_hour: h,
            tm_mday: d,
            tm_mon: mon - 1,
            tm_year: y - 1900,
            tm_wday: 0,
            tm_yday: d,
            tm_isdst: 0,
            tm_utcoff: 0,
            tm_nsec: 0,
        }
    }

    fn this_year() -> i32 {
        time::now_utc().tm_year
    }

    fn move_to_this_year(mut tm: Tm) -> Tm {
        tm.tm_year = this_year();
        tm
    }

    fn set_time_zone(tz: &str) {
        env::set_var("TZ", tz);
        time::tzset();
    }

    #[test]
    fn parse() {
        let time = parse_time_str("19881211t152000z").unwrap();
        let tm = time::at_utc(time);
        assert_eq!(tm.tm_year, 88);
        assert_eq!(tm.tm_mon, 11);  // month in [0 - 11]
        assert_eq!(tm.tm_mday, 11);
        assert_eq!(tm.tm_hour, 15);
        assert_eq!(tm.tm_min, 20);
        assert_eq!(tm.tm_sec, 0);
    }

    #[test]
    fn display_utc() {
        let time = move_to_this_year(time(1988, 12, 11, 15, 20, 0));
        assert_eq!(format!("{}", time.to_timespec().into_utc_display()), "Dec 11 15:20");
    }

    // NOTE: changing the time zone is global in the process,
    //       tests are run in parallel,
    //       so, to avoid race conditions in tests requiring a certain timezone you have two
    //       options:
    //       - put every test in the same `test` function
    //       - use a global mutex
    //       we are now using the first option, since the following is the only test requiring a
    //       certain time zone to be set.
    #[test]
    fn display_local() {
        let time = move_to_this_year(time(1988, 12, 11, 15, 20, 0));
        set_time_zone("Europe/London");
        assert_eq!(format!("{}", time.to_timespec().into_local_display()), "Dec 11 15:20");
        set_time_zone("Europe/Rome");
        assert_eq!(format!("{}", time.to_timespec().into_local_display()), "Dec 11 16:20");
    }

    #[test]
    fn display_past_year() {
        let time = time(1988, 12, 11, 15, 20, 0);
        assert_eq!(format!("{}", time.to_timespec().into_utc_display()), "Dec 11  1988");
    }

    #[test]
    fn parse_display_past_year() {
        let time = parse_time_str("19881211t152000z").unwrap();
        assert_eq!(format!("{}", time.into_utc_display()), "Dec 11  1988");
    }
}
<|endoftext|>


<commit_before>extern crate rayon;

use std::rc::Rc;

fn main() {
    rayon::join(|| Rc::new(22), || Rc::new(23));
    //~^ ERROR E0277
    //~| ERROR E0277
}
<commit_msg>Split up the test of join returning Rc<commit_after>extern crate rayon;

use std::rc::Rc;

fn main() {
    rayon::join(|| Rc::new(22), || ()); //~ ERROR E0277
    rayon::join(|| (), || Rc::new(23)); //~ ERROR E0277
}
<|endoftext|>


<commit_before>/// Represents the color preferences for program output
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ColorChoice {
    /// Enables colored output only when the output is going to a terminal or TTY.
    ///
    /// **NOTE:** This is the default behavior of `clap`.
    ///
    /// # Platform Specific
    ///
    /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms).
    ///
    /// # Examples
    ///
    #[cfg_attr(not(feature = "color"), doc = " ```ignore")]
    #[cfg_attr(feature = "color", doc = " ```no_run")]
    /// # use clap::{Command, ColorChoice};
    /// Command::new("myprog")
    ///     .color(ColorChoice::Auto)
    ///     .get_matches();
    /// ```
    Auto,

    /// Enables colored output regardless of whether or not the output is going to a terminal/TTY.
    ///
    /// # Platform Specific
    ///
    /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms).
    ///
    /// # Examples
    ///
    #[cfg_attr(not(feature = "color"), doc = " ```ignore")]
    #[cfg_attr(feature = "color", doc = " ```no_run")]
    /// # use clap::{Command, ColorChoice};
    /// Command::new("myprog")
    ///     .color(ColorChoice::Always)
    ///     .get_matches();
    /// ```
    Always,

    /// Disables colored output no matter if the output is going to a terminal/TTY, or not.
    ///
    /// # Platform Specific
    ///
    /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms)
    ///
    /// # Examples
    ///
    #[cfg_attr(not(feature = "color"), doc = " ```ignore")]
    #[cfg_attr(feature = "color", doc = " ```no_run")]
    /// # use clap::{Command, ColorChoice};
    /// Command::new("myprog")
    ///     .color(ColorChoice::Never)
    ///     .get_matches();
    /// ```
    Never,
}

impl Default for ColorChoice {
    fn default() -> Self {
        Self::Auto
    }
}
<commit_msg>feat(derive): Implement ValueEnum for ColorChoice<commit_after>use crate::builder::PossibleValue;
use crate::derive::ValueEnum;

/// Represents the color preferences for program output
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ColorChoice {
    /// Enables colored output only when the output is going to a terminal or TTY.
    ///
    /// **NOTE:** This is the default behavior of `clap`.
    ///
    /// # Platform Specific
    ///
    /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms).
    ///
    /// # Examples
    ///
    #[cfg_attr(not(feature = "color"), doc = " ```ignore")]
    #[cfg_attr(feature = "color", doc = " ```no_run")]
    /// # use clap::{Command, ColorChoice};
    /// Command::new("myprog")
    ///     .color(ColorChoice::Auto)
    ///     .get_matches();
    /// ```
    Auto,

    /// Enables colored output regardless of whether or not the output is going to a terminal/TTY.
    ///
    /// # Platform Specific
    ///
    /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms).
    ///
    /// # Examples
    ///
    #[cfg_attr(not(feature = "color"), doc = " ```ignore")]
    #[cfg_attr(feature = "color", doc = " ```no_run")]
    /// # use clap::{Command, ColorChoice};
    /// Command::new("myprog")
    ///     .color(ColorChoice::Always)
    ///     .get_matches();
    /// ```
    Always,

    /// Disables colored output no matter if the output is going to a terminal/TTY, or not.
    ///
    /// # Platform Specific
    ///
    /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms)
    ///
    /// # Examples
    ///
    #[cfg_attr(not(feature = "color"), doc = " ```ignore")]
    #[cfg_attr(feature = "color", doc = " ```no_run")]
    /// # use clap::{Command, ColorChoice};
    /// Command::new("myprog")
    ///     .color(ColorChoice::Never)
    ///     .get_matches();
    /// ```
    Never,
}

impl Default for ColorChoice {
    fn default() -> Self {
        Self::Auto
    }
}

impl ValueEnum for ColorChoice {
    fn value_variants<'a>() -> &'a [Self] {
        &[Self::Auto, Self::Always, Self::Never]
    }

    fn to_possible_value(&self) -> Option<PossibleValue> {
        Some(match self {
            Self::Auto => {
                PossibleValue::new("auto").help("Use colored output if writing to a terminal/TTY")
            }
            Self::Always => PossibleValue::new("always").help("Always use colored output"),
            Self::Never => PossibleValue::new("never").help("Never use colored output"),
        })
    }
}
<|endoftext|>