<commit_before>//! # Dynamic parsing within trees 🌲 🌳 🌴
//!
//! Target of this library is to provide a flexible approach in parsing data. This will mainly be
//! done within [arena](https://en.wikipedia.org/wiki/Region-based_memory_management) based
//! [parser trees](https://en.wikipedia.org/wiki/Parse_tree) which can be modified during runtime.
//! Every parser is using the [nom](https://github.com/Geal/nom) framework for the actual parsing
//! work. A complete source code example can be found within the
//! [`src/example`](https://github.com/saschagrunert/peel/tree/master/src/example) directory of the
//! crate.
#![deny(missing_docs)]

#[macro_use]
extern crate nom;

#[macro_use]
extern crate log;
extern crate petgraph;
extern crate mowl;

#[macro_use]
pub mod error;
pub mod parser;
pub mod example;

use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

use log::LogLevel;
use nom::{IResult, generate_colors, prepare_errors, print_codes, print_offsets};

use petgraph::{Graph, Direction};
use petgraph::dot::{Dot, Config};
use petgraph::graph::NodeIndex;
use petgraph::stable_graph::StableGraph;
use petgraph::visit::{EdgeRef, IntoEdgeReferences};

use prelude::*;
use parser::ParserBox;

/// Provides sensible imports at all
pub mod prelude {
    pub use super::Peel;
    pub use error::{PeelResult, PeelError, ErrorType};
    pub use parser::Parser;
}

/// The main peeling structure
pub struct Peel<R, V, D> {
    /// The memory arena of the tree
    pub graph: StableGraph<ParserBox<R, V, D>, ()>,

    /// The first node added will be the root
    pub root: Option<NodeIndex>,

    /// Additional data for which can be shared accross the parsers
    pub data: Option<D>,
}

impl<R, V, D> Peel<R, V, D>
    where V: fmt::Display
{
    /// Create a new empty `Peel` instance
    pub fn new() -> Self {
        Peel {
            graph: StableGraph::new(),
            root: None,
            data: None,
        }
    }

    /// Set the global log level for reporting
    pub fn set_log_level(&mut self, level: LogLevel) {
        // Setup the logger if not already set
        if mowl::init_with_level(level).is_err() {
            warn!("Logger already set.");
        };
        info!("Log level set to: {:?}", level);
    }

    /// Create a new boxed Parser and return a corresponding Node
    pub fn new_parser<T>(&mut self, parser: T) -> NodeIndex
        where T: Parser<D, Result = R, Variant = V> + Send + Sync + 'static
    {
        info!("New parser: {}", parser.variant());

        // Create a new node
        let new_node = self.graph.add_node(Box::new(parser));

        // Check if the root node is already set. If not, then this will be the root
        if self.root.is_none() {
            self.root = Some(new_node);
        }

        // Return the shiny new node
        new_node
    }

    /// Append the second node to the first one within the current tree structure
    pub fn link(&mut self, left: NodeIndex, right: NodeIndex) {
        info!("Link: {} → {}", self.graph[left], self.graph[right]);
        self.graph.add_edge(left, right, ());
    }

    /// Create a new parser and link it with the provided node
    pub fn link_new_parser<T>(&mut self, left: NodeIndex, parser: T) -> NodeIndex
        where T: Parser<D, Result = R, Variant = V> + Send + Sync + 'static
    {
        // Create a new node
        let new_parser = self.new_parser(parser);

        // Append the node to the given node
        self.link(left, new_parser);

        // Return the parser
        new_parser
    }

    /// Convenient function for recursive traversal with the root as starting point
    ///
    /// # Errors
    /// When no tree root was found or the first parser already fails.
    pub fn traverse(&mut self, input: &[u8], result: Vec<R>) -> PeelResult<Vec<R>> {
        match self.root {
            Some(node) => self.traverse_recursive(node, input, result),
            None => bail!(ErrorType::NoTreeRoot, "No tree root found"),
        }
    }

    /// Do parsing until all possible paths failed. This is equivalent in finding the deepest
    /// possible parsing result within the tree. The result will be assembled together in the
    /// given result vector, which will be returned at the end.
    ///
    /// # Errors
    /// When the first parser already fails.
    pub fn traverse_recursive(&mut self, node_id: NodeIndex, input: &[u8], mut result: Vec<R>) -> PeelResult<Vec<R>> {

        let (left_input, error) = {
            // Get the values from the graph structure
            let parser = &mut self.graph[node_id];

            // Do the actual parsing work
            match parser.parse(input,
                               Some(&result),
                               if let Some(ref mut data) = self.data {
                                   Some(data)
                               } else {
                                   None
                               }) {
                // Parsing succeed
                IResult::Done(left_input, parser_result) => {
                    debug!("{} parsing succeed, left input length: {}",
                           parser.variant(),
                           left_input.len());
                    // Adapt the result
                    result.push(parser_result);
                    (left_input, None)
                }

                // Parsing failed
                error => {
                    trace!("Failed parser: {}", parser.variant());
                    if Some(node_id) == self.root {
                        bail!(ErrorType::RootParserFailed, "No parser succeed at all");
                    }
                    (input, Some(error))
                }
            }
        };

        match error {
            // Display the parsing error if needed
            Some(error) => {
                if log_enabled!(log::LogLevel::Trace) {
                    self.display_error(input, error);
                }
            }

            // Continue traversal if needed
            _ => {
                let mut edges = self.graph.neighbors_directed(node_id, Direction::Outgoing).detach();
                while let Some(node) = edges.next_node(&self.graph) {
                    // Save the previous result length
                    let prev_len = result.len();

                    // Do the recursion
                    result = self.traverse_recursive(node, left_input, result)?;

                    // Stop going deeper if something was added to the result
                    if prev_len < result.len() {
                        break;
                    }
                }
            }
        }

        // Return the current result
        Ok(result)
    }

    /// Create a graphviz `graph.dot` file representation in the current directory
    pub fn create_dot_file(&mut self) -> PeelResult<()> {
        // Create a temporarily graph for conversion
        let mut graph = Graph::<_, ()>::new();

        // Convert the nodes
        for node_id in self.graph.node_indices() {
            let parser = &self.graph[node_id];
            graph.add_node(format!("{}", parser.variant()));
        }

        // Convert the edges
        for edge in self.graph.edge_references() {
            graph.add_edge(edge.source(), edge.target(), ());
        }

        let mut f = File::create("graph.dot")?;
        f.write_all(format!("{:?}", Dot::with_config(&graph, &[Config::EdgeNoLabel])).as_bytes())?;
        Ok(())
    }

    /// Display an error from a parser
    pub fn display_error(&self, input: &[u8], res: IResult<&[u8], R>) {
        let mut h: HashMap<u32, &str> = HashMap::new();
        let parsers = ["Custom",
                       "Tag",
                       "MapRes",
                       "MapOpt",
                       "Alt",
                       "IsNot",
                       "IsA",
                       "SeparatedList",
                       "SeparatedNonEmptyList",
                       "Many1",
                       "Count",
                       "TakeUntilAndConsume",
                       "TakeUntil",
                       "TakeUntilEitherAndConsume",
                       "TakeUntilEither",
                       "LengthValue",
                       "TagClosure",
                       "Alpha",
                       "Digit",
                       "AlphaNumeric",
                       "Space",
                       "MultiSpace",
                       "LengthValueFn",
                       "Eof",
                       "ExprOpt",
                       "ExprRes",
                       "CondReduce",
                       "Switch",
                       "TagBits",
                       "OneOf",
                       "NoneOf",
                       "Char",
                       "CrLf",
                       "RegexpMatch",
                       "RegexpMatches",
                       "RegexpFind",
                       "RegexpCapture",
                       "RegexpCaptures",
                       "TakeWhile1",
                       "Complete",
                       "Fix",
                       "Escaped",
                       "EscapedTransform",
                       "TagStr",
                       "IsNotStr",
                       "IsAStr",
                       "TakeWhile1Str",
                       "NonEmpty",
                       "ManyMN",
                       "TakeUntilAndConsumeStr",
                       "HexDigit",
                       "TakeUntilStr",
                       "OctDigit",
                       "Many0",
                       "Not",
                       "Permutation",
                       "ManyTill"];

        for (i, literal) in parsers.iter().enumerate() {
            h.insert(i as u32, literal);
        }

        if let Some(v) = prepare_errors(input, res) {
            let colors = generate_colors(&v);
            println!("Colors: {}", print_codes(colors, h));
            println!("Dump: \n{}", print_offsets(input, 0, &v));
        }
    }
}
<commit_msg>Fixed wrong info message<commit_after>//! # Dynamic parsing within trees 🌲 🌳 🌴
//!
//! Target of this library is to provide a flexible approach in parsing data. This will mainly be
//! done within [arena](https://en.wikipedia.org/wiki/Region-based_memory_management) based
//! [parser trees](https://en.wikipedia.org/wiki/Parse_tree) which can be modified during runtime.
//! Every parser is using the [nom](https://github.com/Geal/nom) framework for the actual parsing
//! work. A complete source code example can be found within the
//! [`src/example`](https://github.com/saschagrunert/peel/tree/master/src/example) directory of the
//! crate.
#![deny(missing_docs)]

#[macro_use]
extern crate nom;

#[macro_use]
extern crate log;
extern crate petgraph;
extern crate mowl;

#[macro_use]
pub mod error;
pub mod parser;
pub mod example;

use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

use log::LogLevel;
use nom::{IResult, generate_colors, prepare_errors, print_codes, print_offsets};

use petgraph::{Graph, Direction};
use petgraph::dot::{Dot, Config};
use petgraph::graph::NodeIndex;
use petgraph::stable_graph::StableGraph;
use petgraph::visit::{EdgeRef, IntoEdgeReferences};

use prelude::*;
use parser::ParserBox;

/// Provides sensible imports at all
pub mod prelude {
    pub use super::Peel;
    pub use error::{PeelResult, PeelError, ErrorType};
    pub use parser::Parser;
}

/// The main peeling structure
pub struct Peel<R, V, D> {
    /// The memory arena of the tree
    pub graph: StableGraph<ParserBox<R, V, D>, ()>,

    /// The first node added will be the root
    pub root: Option<NodeIndex>,

    /// Additional data for which can be shared accross the parsers
    pub data: Option<D>,
}

impl<R, V, D> Peel<R, V, D>
    where V: fmt::Display
{
    /// Create a new empty `Peel` instance
    pub fn new() -> Self {
        Peel {
            graph: StableGraph::new(),
            root: None,
            data: None,
        }
    }

    /// Set the global log level for reporting
    pub fn set_log_level(&mut self, level: LogLevel) {
        // Setup the logger if not already set
        if mowl::init_with_level(level).is_err() {
            warn!("Logger already set.");
        } else {
            info!("Log level set to: {:?}", level);
        }
    }

    /// Create a new boxed Parser and return a corresponding Node
    pub fn new_parser<T>(&mut self, parser: T) -> NodeIndex
        where T: Parser<D, Result = R, Variant = V> + Send + Sync + 'static
    {
        info!("New parser: {}", parser.variant());

        // Create a new node
        let new_node = self.graph.add_node(Box::new(parser));

        // Check if the root node is already set. If not, then this will be the root
        if self.root.is_none() {
            self.root = Some(new_node);
        }

        // Return the shiny new node
        new_node
    }

    /// Append the second node to the first one within the current tree structure
    pub fn link(&mut self, left: NodeIndex, right: NodeIndex) {
        info!("Link: {} → {}", self.graph[left], self.graph[right]);
        self.graph.add_edge(left, right, ());
    }

    /// Create a new parser and link it with the provided node
    pub fn link_new_parser<T>(&mut self, left: NodeIndex, parser: T) -> NodeIndex
        where T: Parser<D, Result = R, Variant = V> + Send + Sync + 'static
    {
        // Create a new node
        let new_parser = self.new_parser(parser);

        // Append the node to the given node
        self.link(left, new_parser);

        // Return the parser
        new_parser
    }

    /// Convenient function for recursive traversal with the root as starting point
    ///
    /// # Errors
    /// When no tree root was found or the first parser already fails.
    pub fn traverse(&mut self, input: &[u8], result: Vec<R>) -> PeelResult<Vec<R>> {
        match self.root {
            Some(node) => self.traverse_recursive(node, input, result),
            None => bail!(ErrorType::NoTreeRoot, "No tree root found"),
        }
    }

    /// Do parsing until all possible paths failed. This is equivalent in finding the deepest
    /// possible parsing result within the tree. The result will be assembled together in the
    /// given result vector, which will be returned at the end.
    ///
    /// # Errors
    /// When the first parser already fails.
    pub fn traverse_recursive(&mut self, node_id: NodeIndex, input: &[u8], mut result: Vec<R>) -> PeelResult<Vec<R>> {

        let (left_input, error) = {
            // Get the values from the graph structure
            let parser = &mut self.graph[node_id];

            // Do the actual parsing work
            match parser.parse(input,
                               Some(&result),
                               if let Some(ref mut data) = self.data {
                                   Some(data)
                               } else {
                                   None
                               }) {
                // Parsing succeed
                IResult::Done(left_input, parser_result) => {
                    debug!("{} parsing succeed, left input length: {}",
                           parser.variant(),
                           left_input.len());
                    // Adapt the result
                    result.push(parser_result);
                    (left_input, None)
                }

                // Parsing failed
                error => {
                    trace!("Failed parser: {}", parser.variant());
                    if Some(node_id) == self.root {
                        bail!(ErrorType::RootParserFailed, "No parser succeed at all");
                    }
                    (input, Some(error))
                }
            }
        };

        match error {
            // Display the parsing error if needed
            Some(error) => {
                if log_enabled!(log::LogLevel::Trace) {
                    self.display_error(input, error);
                }
            }

            // Continue traversal if needed
            _ => {
                let mut edges = self.graph.neighbors_directed(node_id, Direction::Outgoing).detach();
                while let Some(node) = edges.next_node(&self.graph) {
                    // Save the previous result length
                    let prev_len = result.len();

                    // Do the recursion
                    result = self.traverse_recursive(node, left_input, result)?;

                    // Stop going deeper if something was added to the result
                    if prev_len < result.len() {
                        break;
                    }
                }
            }
        }

        // Return the current result
        Ok(result)
    }

    /// Create a graphviz `graph.dot` file representation in the current directory
    pub fn create_dot_file(&mut self) -> PeelResult<()> {
        // Create a temporarily graph for conversion
        let mut graph = Graph::<_, ()>::new();

        // Convert the nodes
        for node_id in self.graph.node_indices() {
            let parser = &self.graph[node_id];
            graph.add_node(format!("{}", parser.variant()));
        }

        // Convert the edges
        for edge in self.graph.edge_references() {
            graph.add_edge(edge.source(), edge.target(), ());
        }

        let mut f = File::create("graph.dot")?;
        f.write_all(format!("{:?}", Dot::with_config(&graph, &[Config::EdgeNoLabel])).as_bytes())?;
        Ok(())
    }

    /// Display an error from a parser
    pub fn display_error(&self, input: &[u8], res: IResult<&[u8], R>) {
        let mut h: HashMap<u32, &str> = HashMap::new();
        let parsers = ["Custom",
                       "Tag",
                       "MapRes",
                       "MapOpt",
                       "Alt",
                       "IsNot",
                       "IsA",
                       "SeparatedList",
                       "SeparatedNonEmptyList",
                       "Many1",
                       "Count",
                       "TakeUntilAndConsume",
                       "TakeUntil",
                       "TakeUntilEitherAndConsume",
                       "TakeUntilEither",
                       "LengthValue",
                       "TagClosure",
                       "Alpha",
                       "Digit",
                       "AlphaNumeric",
                       "Space",
                       "MultiSpace",
                       "LengthValueFn",
                       "Eof",
                       "ExprOpt",
                       "ExprRes",
                       "CondReduce",
                       "Switch",
                       "TagBits",
                       "OneOf",
                       "NoneOf",
                       "Char",
                       "CrLf",
                       "RegexpMatch",
                       "RegexpMatches",
                       "RegexpFind",
                       "RegexpCapture",
                       "RegexpCaptures",
                       "TakeWhile1",
                       "Complete",
                       "Fix",
                       "Escaped",
                       "EscapedTransform",
                       "TagStr",
                       "IsNotStr",
                       "IsAStr",
                       "TakeWhile1Str",
                       "NonEmpty",
                       "ManyMN",
                       "TakeUntilAndConsumeStr",
                       "HexDigit",
                       "TakeUntilStr",
                       "OctDigit",
                       "Many0",
                       "Not",
                       "Permutation",
                       "ManyTill"];

        for (i, literal) in parsers.iter().enumerate() {
            h.insert(i as u32, literal);
        }

        if let Some(v) = prepare_errors(input, res) {
            let colors = generate_colors(&v);
            println!("Colors: {}", print_codes(colors, h));
            println!("Dump: \n{}", print_offsets(input, 0, &v));
        }
    }
}
<|endoftext|>


<commit_before>//! Structured application logging.
//!
//! This module provides:
//!
//!  * The `emit!()` family of macros, for recording application events in an easily machine-readable format
//!  * Collectors for transmitting these events to back-end logging servers
//!
//! The emit macros are "structured" versions of the ones in the widely-used `log` crate. The `log` crate doesn't preserve the structure
//! of the events that are written through it. For example:
//!
//! ```ignore
//! info!("Hello, {}!", env::var("USERNAME").unwrap());
//! ```
//!
//! This writes `"Hello, nblumhardt!"` to the log as an block of text, which can't later be broken apart to reveal the username except
//! with regular expressions.
//!
//! The arguments passed to `emit` are named:
//!
//! ```ignore
//! eminfo!("Hello, {}!", user: env::var("USERNAME").unwrap());
//! ```
//!
//! This event can be rendered into text identically to the `log` example, but structured data collectors also capture the
//! aguments as a key/value property pairs.
//!
//! ```js
//! {
//!   "timestamp": "2016-03-17T00:17:01Z",
//!   "messageTemplate": "Hello, {user}!",
//!   "properties": {
//!     "user": "nblumhardt",
//!     "target": "example_app"
//!   }
//! }
//! ```
//!
//! Back-ends like Elasticsearch, Seq, and Splunk use these in queries such as `user == "nblumhardt"` without up-front log parsing.
//!
//! Arguments are captured using `serde`, so there's the potential for complex values to be logged so long as they're `serde::ser::Serialize`.
//!
//! Further, because the template (format) itself is captured, it can be hashed to compute an "event type" for precisely finding
//! all occurrences of the event regardless of the value of the `user` argument.
//!
//! # Examples
//!
//! The example below writes events to stdout.
//!
//! ```
//! #[macro_use]
//! extern crate emit;
//! # extern crate log;
//!
//! use std::env;
//! use emit::PipelineBuilder;
//! use emit::collectors::stdio::StdioCollector;
//!
//! fn main() {
//!     let _flush = PipelineBuilder::new()
//!         .write_to(StdioCollector::new())
//!         .init();
//!
//!     eminfo!("Hello, {}!", name: env::var("USERNAME").unwrap());
//! }
//! ```
//!
//! Output:
//!
//! ```text
//! emit 2016-03-24T05:03:36Z Hello, {name}!
//!   name: "nblumhardt"
//!   target: "example_app"
//!
//! ```

extern crate serde;
extern crate serde_json;
extern crate chrono;

#[macro_use]
extern crate hyper;

#[macro_use]
extern crate log;

pub mod templates;
pub mod events;
pub mod pipeline;
pub mod collectors;
pub mod enrichers;

/// Re-exports `log::LogLevel` so that users can initialize the emit
/// crate without extra imports.
pub use log::LogLevel;

/// Re-export `pipeline::builder::PipelineBuilder` so that clients don't need to
/// fully-qualify the hierarchy.
pub use pipeline::builder::PipelineBuilder;

#[macro_export]
#[doc(hidden)]
macro_rules! __emit_get_event_data {
    ($target:expr, $s:expr, $( $n:ident: $v:expr ),* ) => {{
        #[allow(unused_imports)]
        use std::fmt::Write;
        use std::collections;

        // Underscores avoid the unused_mut warning
        let mut _names: Vec<&str> = vec![];
        let mut properties: collections::BTreeMap<&'static str, String> = collections::BTreeMap::new();

        $(
            _names.push(stringify!($n));
            properties.insert(stringify!($n), $crate::events::capture_property_value(&$v));
        )*

        properties.insert("target", $crate::events::capture_property_value(&$target));

        let template = $crate::templates::MessageTemplate::from_format($s, &_names);

        (template, properties)
    }};
}

/// Emit an event to the ambient pipeline.
///
/// # Examples
///
/// The event below collects a `user` property and is emitted if the pipeline level includes
/// `LogLevel::Info`.
///
/// ```ignore
/// emit!(emit::LogLevel::Info, "Hello, {}!", user: env::var("USERNAME").unwrap());
/// ```
///
/// A `target` expression may be specified if required. When omitted the `target` property
/// will carry the current module name.
///
/// ```ignore
/// emit!(target: "greetings", emit::LogLevel::Info, "Hello, {}!", user: env::var("USERNAME").unwrap());
/// ```
#[macro_export]
macro_rules! emit {
    (target: $target:expr, $lvl:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        let lvl = $lvl;
        if $crate::pipeline::ambient::is_enabled(lvl) {
            let (template, properties) = __emit_get_event_data!($target, $s, $($n: $v),*);
            let event = $crate::events::Event::new_now(lvl, template, properties);
            $crate::pipeline::ambient::emit(event);
        }
    }};

    ($lvl:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        emit!(target: module_path!(), $lvl, $s, $($n: $v),*);
    }};
}

/// Emit an error event to the ambient pipeline.
///
/// # Examples
///
/// The example below will be emitted at the `emit::LogLevel::Error` level.
///
/// ```ignore
/// emerror!("Could not start {} on {}", cmd: "emitd", machine: "s123456");
/// ```
#[macro_export]
macro_rules! emerror {
    (target: $target:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(target: $target, log::LogLevel::Error, $s, $($n: $v),*);
    }};

    ($s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(log::LogLevel::Error, $s, $($n: $v),*);
    }};
}

/// Emit a warning event to the ambient pipeline.
///
/// # Examples
///
/// The example below will be emitted at the `emit::LogLevel::Warn` level.
///
/// ```ignore
/// emwarn!("SQL query took {} ms", elapsed: 7890);
/// ```
#[macro_export]
macro_rules! emwarn {
    (target: $target:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(target: $target, log::LogLevel::Warn, $s, $($n: $v),*);
    }};

    ($s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(log::LogLevel::Warn, $s, $($n: $v),*);
    }};
}

/// Emit an informational event to the ambient pipeline.
///
/// # Examples
///
/// The example below will be emitted at the `emit::LogLevel::Info` level.
///
/// ```ignore
/// eminfo!("Hello, {}!", user: env::var("USERNAME").unwrap());
/// ```
#[macro_export]
macro_rules! eminfo {
    (target: $target:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(target: $target, log::LogLevel::Info, $s, $($n: $v),*);
    }};

    ($s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(log::LogLevel::Info, $s, $($n: $v),*);
    }};
}

/// Emit a debugging event to the ambient pipeline.
///
/// # Examples
///
/// The example below will be emitted at the `emit::LogLevel::Debug` level.
///
/// ```ignore
/// emdebug!("Opening config file {}", filename: "dir/config.json");
/// ```
#[macro_export]
macro_rules! emdebug {
    (target: $target:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(target: $target, log::LogLevel::Debug, $s, $($n: $v),*);
    }};

    ($s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(log::LogLevel::Debug, $s, $($n: $v),*);
    }};
}

/// Emit a trace event to the ambient pipeline.
///
/// # Examples
///
/// The example below will be emitted at the `emit::LogLevel::Trace` level.
///
/// ```ignore
/// emdtrace!("{} called with arg {}", method: "start_frobbles()", count: 123);
/// ```
#[macro_export]
macro_rules! emtrace {
    (target: $target:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(target: $target, log::LogLevel::Trace, $s, $($n: $v),*);
    }};

    ($s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(log::LogLevel::Trace, $s, $($n: $v),*);
    }};
}

#[cfg(test)]
mod tests {
    use collectors::stdio;
    //use collectors::seq;
    use enrichers::fixed_property::FixedPropertyEnricher;
    use pipeline::builder::PipelineBuilder;
    use std::env;
    use log;

    #[test]
    fn unparameterized_templates_are_captured() {
        let (template, properties) = __emit_get_event_data!("t", "Starting...",);
        assert_eq!(template.text(), "Starting...");
        assert_eq!(properties.len(), 1);
    }

    #[test]
    fn template_and_properties_are_captured() {
        let u = "nblumhardt";
        let q = 42;

        let (template, properties) = __emit_get_event_data!("t", "User {} exceeded quota of {}!", user: u, quota: q);
        assert_eq!(template.text(), "User {user} exceeded quota of {quota}!");
        assert_eq!(properties.get("user"), Some(&"\"nblumhardt\"".to_owned()));
        assert_eq!(properties.get("quota"), Some(&"42".to_owned()));
        assert_eq!(properties.len(), 3);
    }

    #[test]
    fn emitted_events_are_flushed() {
        let _flush = PipelineBuilder::new()
            .at_level(log::LogLevel::Info)
            .pipe(Box::new(FixedPropertyEnricher::new("app", &"Test")))
            .write_to(stdio::StdioCollector::new())
            .init();

        eminfo!("Hello, {} at {} in {}!", name: env::var("USERNAME").unwrap(), time: 2139, room: "office");
    }
}
<commit_msg>make env::var tests pass on nix<commit_after>//! Structured application logging.
//!
//! This module provides:
//!
//!  * The `emit!()` family of macros, for recording application events in an easily machine-readable format
//!  * Collectors for transmitting these events to back-end logging servers
//!
//! The emit macros are "structured" versions of the ones in the widely-used `log` crate. The `log` crate doesn't preserve the structure
//! of the events that are written through it. For example:
//!
//! ```ignore
//! info!("Hello, {}!", env::var("USERNAME").unwrap());
//! ```
//!
//! This writes `"Hello, nblumhardt!"` to the log as an block of text, which can't later be broken apart to reveal the username except
//! with regular expressions.
//!
//! The arguments passed to `emit` are named:
//!
//! ```ignore
//! eminfo!("Hello, {}!", user: env::var("USERNAME").unwrap());
//! ```
//!
//! This event can be rendered into text identically to the `log` example, but structured data collectors also capture the
//! aguments as a key/value property pairs.
//!
//! ```js
//! {
//!   "timestamp": "2016-03-17T00:17:01Z",
//!   "messageTemplate": "Hello, {user}!",
//!   "properties": {
//!     "user": "nblumhardt",
//!     "target": "example_app"
//!   }
//! }
//! ```
//!
//! Back-ends like Elasticsearch, Seq, and Splunk use these in queries such as `user == "nblumhardt"` without up-front log parsing.
//!
//! Arguments are captured using `serde`, so there's the potential for complex values to be logged so long as they're `serde::ser::Serialize`.
//!
//! Further, because the template (format) itself is captured, it can be hashed to compute an "event type" for precisely finding
//! all occurrences of the event regardless of the value of the `user` argument.
//!
//! # Examples
//!
//! The example below writes events to stdout.
//!
//! ```
//! #[macro_use]
//! extern crate emit;
//! # extern crate log;
//!
//! use std::env;
//! use emit::PipelineBuilder;
//! use emit::collectors::stdio::StdioCollector;
//!
//! fn main() {
//!     let _flush = PipelineBuilder::new()
//!         .write_to(StdioCollector::new())
//!         .init();
//!
//!     eminfo!("Hello, {}!", name: env::var("USERNAME").unwrap_or("User".to_string()));
//! }
//! ```
//!
//! Output:
//!
//! ```text
//! emit 2016-03-24T05:03:36Z Hello, {name}!
//!   name: "nblumhardt"
//!   target: "example_app"
//!
//! ```

extern crate serde;
extern crate serde_json;
extern crate chrono;

#[macro_use]
extern crate hyper;

#[macro_use]
extern crate log;

pub mod templates;
pub mod events;
pub mod pipeline;
pub mod collectors;
pub mod enrichers;

/// Re-exports `log::LogLevel` so that users can initialize the emit
/// crate without extra imports.
pub use log::LogLevel;

/// Re-export `pipeline::builder::PipelineBuilder` so that clients don't need to
/// fully-qualify the hierarchy.
pub use pipeline::builder::PipelineBuilder;

#[macro_export]
#[doc(hidden)]
macro_rules! __emit_get_event_data {
    ($target:expr, $s:expr, $( $n:ident: $v:expr ),* ) => {{
        #[allow(unused_imports)]
        use std::fmt::Write;
        use std::collections;

        // Underscores avoid the unused_mut warning
        let mut _names: Vec<&str> = vec![];
        let mut properties: collections::BTreeMap<&'static str, String> = collections::BTreeMap::new();

        $(
            _names.push(stringify!($n));
            properties.insert(stringify!($n), $crate::events::capture_property_value(&$v));
        )*

        properties.insert("target", $crate::events::capture_property_value(&$target));

        let template = $crate::templates::MessageTemplate::from_format($s, &_names);

        (template, properties)
    }};
}

/// Emit an event to the ambient pipeline.
///
/// # Examples
///
/// The event below collects a `user` property and is emitted if the pipeline level includes
/// `LogLevel::Info`.
///
/// ```ignore
/// emit!(emit::LogLevel::Info, "Hello, {}!", user: env::var("USERNAME").unwrap());
/// ```
///
/// A `target` expression may be specified if required. When omitted the `target` property
/// will carry the current module name.
///
/// ```ignore
/// emit!(target: "greetings", emit::LogLevel::Info, "Hello, {}!", user: env::var("USERNAME").unwrap());
/// ```
#[macro_export]
macro_rules! emit {
    (target: $target:expr, $lvl:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        let lvl = $lvl;
        if $crate::pipeline::ambient::is_enabled(lvl) {
            let (template, properties) = __emit_get_event_data!($target, $s, $($n: $v),*);
            let event = $crate::events::Event::new_now(lvl, template, properties);
            $crate::pipeline::ambient::emit(event);
        }
    }};

    ($lvl:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        emit!(target: module_path!(), $lvl, $s, $($n: $v),*);
    }};
}

/// Emit an error event to the ambient pipeline.
///
/// # Examples
///
/// The example below will be emitted at the `emit::LogLevel::Error` level.
///
/// ```ignore
/// emerror!("Could not start {} on {}", cmd: "emitd", machine: "s123456");
/// ```
#[macro_export]
macro_rules! emerror {
    (target: $target:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(target: $target, log::LogLevel::Error, $s, $($n: $v),*);
    }};

    ($s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(log::LogLevel::Error, $s, $($n: $v),*);
    }};
}

/// Emit a warning event to the ambient pipeline.
///
/// # Examples
///
/// The example below will be emitted at the `emit::LogLevel::Warn` level.
///
/// ```ignore
/// emwarn!("SQL query took {} ms", elapsed: 7890);
/// ```
#[macro_export]
macro_rules! emwarn {
    (target: $target:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(target: $target, log::LogLevel::Warn, $s, $($n: $v),*);
    }};

    ($s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(log::LogLevel::Warn, $s, $($n: $v),*);
    }};
}

/// Emit an informational event to the ambient pipeline.
///
/// # Examples
///
/// The example below will be emitted at the `emit::LogLevel::Info` level.
///
/// ```ignore
/// eminfo!("Hello, {}!", user: env::var("USERNAME").unwrap());
/// ```
#[macro_export]
macro_rules! eminfo {
    (target: $target:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(target: $target, log::LogLevel::Info, $s, $($n: $v),*);
    }};

    ($s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(log::LogLevel::Info, $s, $($n: $v),*);
    }};
}

/// Emit a debugging event to the ambient pipeline.
///
/// # Examples
///
/// The example below will be emitted at the `emit::LogLevel::Debug` level.
///
/// ```ignore
/// emdebug!("Opening config file {}", filename: "dir/config.json");
/// ```
#[macro_export]
macro_rules! emdebug {
    (target: $target:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(target: $target, log::LogLevel::Debug, $s, $($n: $v),*);
    }};

    ($s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(log::LogLevel::Debug, $s, $($n: $v),*);
    }};
}

/// Emit a trace event to the ambient pipeline.
///
/// # Examples
///
/// The example below will be emitted at the `emit::LogLevel::Trace` level.
///
/// ```ignore
/// emdtrace!("{} called with arg {}", method: "start_frobbles()", count: 123);
/// ```
#[macro_export]
macro_rules! emtrace {
    (target: $target:expr, $s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(target: $target, log::LogLevel::Trace, $s, $($n: $v),*);
    }};

    ($s:expr, $($n:ident: $v:expr),*) => {{
        #[allow(unused_imports)]
        use log;
        emit!(log::LogLevel::Trace, $s, $($n: $v),*);
    }};
}

#[cfg(test)]
mod tests {
    use collectors::stdio;
    //use collectors::seq;
    use enrichers::fixed_property::FixedPropertyEnricher;
    use pipeline::builder::PipelineBuilder;
    use std::env;
    use log;

    #[test]
    fn unparameterized_templates_are_captured() {
        let (template, properties) = __emit_get_event_data!("t", "Starting...",);
        assert_eq!(template.text(), "Starting...");
        assert_eq!(properties.len(), 1);
    }

    #[test]
    fn template_and_properties_are_captured() {
        let u = "nblumhardt";
        let q = 42;

        let (template, properties) = __emit_get_event_data!("t", "User {} exceeded quota of {}!", user: u, quota: q);
        assert_eq!(template.text(), "User {user} exceeded quota of {quota}!");
        assert_eq!(properties.get("user"), Some(&"\"nblumhardt\"".to_owned()));
        assert_eq!(properties.get("quota"), Some(&"42".to_owned()));
        assert_eq!(properties.len(), 3);
    }

    #[test]
    fn emitted_events_are_flushed() {
        let _flush = PipelineBuilder::new()
            .at_level(log::LogLevel::Info)
            .pipe(Box::new(FixedPropertyEnricher::new("app", &"Test")))
            .write_to(stdio::StdioCollector::new())
            .init();

        eminfo!("Hello, {} at {} in {}!", name: env::var("USERNAME").unwrap_or("User".to_string()), time: 2139, room: "office");
    }
}
<|endoftext|>


<commit_before>//! The main entry point for the Space API server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate iron;
extern crate spaceapi;

pub mod datastore;
pub mod redis_store;

use std::net::Ipv4Addr;
use std::sync::Mutex;
use std::sync::Arc;

use rustc_serialize::json::{Json, ToJson};
use iron::{Request, Response, IronResult, Iron, Set};
use iron::{status, headers, middleware};
use iron::modifiers::Header;

pub use datastore::DataStore;
use spaceapi::Optional::{Value, Absent};

fn build_response_json(status: &spaceapi::Status, people_present: Option<u32>, raspi_temperature: Option<f32>) -> Json {
    let people_present_sensor = match people_present {
        Some(count) => Value(vec![
            spaceapi::PeopleNowPresentSensor {
                value: count,
                location: Value("Hackerspace".to_string()),
                name: Absent,
                description: Absent,
                names: Absent,
            }
        ]),
        None => Absent,
    };

    let temperature_sensor = match raspi_temperature {
        Some(degrees) => Value(vec![
            spaceapi::TemperatureSensor {
                value: degrees,
                unit: "°C".to_string(),
                location: "Basement".to_string(),
                name: Value("Raspberry CPU".to_string()),
                description: Absent,
            }
        ]),
        None => Absent,
    };

    // Create a mutable copy of the status struct and add sensor data.
    let mut status_copy = (*status).clone();
    status_copy.sensors = Value(spaceapi::Sensors {
        people_now_present: people_present_sensor,
        temperature: temperature_sensor,
    });

    // Serialize to JSON
    status_copy.to_json()
}

/// A Space API server instance.
///
/// You can create a new instance using the ``new`` constructor method by
/// passing it the host, the port, the ``Status`` object and a datastore.
///
/// The ``SpaceapiServer`` includes a web server through
/// [Hyper](http://hyper.rs/hyper/hyper/server/index.html). Simply call the ``serve`` method.
pub struct SpaceapiServer {
    host: Ipv4Addr,
    port: u16,
    status: spaceapi::Status,
    datastore: Arc<Mutex<Box<DataStore>>>,
}

impl SpaceapiServer {

    pub fn new(host: Ipv4Addr, port: u16, status: spaceapi::Status, datastore: Arc<Mutex<Box<DataStore>>>) -> SpaceapiServer{
        SpaceapiServer {
            host: host,
            port: port,
            status: status,
            datastore: datastore,
        }
    }

    pub fn serve(self) {
        let host = self.host;
        let port = self.port;
        println!("Starting HTTP server on {}:{}...", host, port);
        Iron::new(self).http((host, port)).unwrap();
    }

}

impl middleware::Handler for SpaceapiServer {

    fn handle(&self, _: &mut Request) -> IronResult<Response> {

        // Fetch data from datastore
        let datastore_clone = self.datastore.clone();
        let datastore_lock = datastore_clone.lock().unwrap();
        let people_present: Option<u32> = match datastore_lock.retrieve("people_present") {
            Ok(v) => match v.parse::<u32>() {
                Ok(i) => Some(i),
                Err(_) => None,
            },
            Err(_) => None,
        };
        let raspi_temperature: Option<f32> = match datastore_lock.retrieve("raspi_temperature") {
            Ok(v) => match v.parse::<f32>() {
                Ok(i) => Some(i),
                Err(_) => None,
            },
            Err(_) => None,
        };

        // Get response body
        let body = build_response_json(&self.status, people_present, raspi_temperature).to_string();

        // Create response
        let mut response = Response::with((status::Ok, body));

        // Set headers
        response.set_mut(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())));
        response.set_mut(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])));
        response.set_mut(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }
}

#[cfg(test)]
mod test {
    extern crate spaceapi;
    extern crate rustc_serialize;

    use super::build_response_json;
    use spaceapi::Optional;
    use rustc_serialize::json::Json;

    fn get_test_data() -> Json {
        // Create minimal status object
        let ref status = spaceapi::Status::new(
            "ourspace".to_string(),
            "https://example.com/logo.png".to_string(),
            "https://example.com/".to_string(),
            spaceapi::Location {
                address: Optional::Value("Street 1, Zürich, Switzerland".to_string()),
                lat: 47.123,
                lon: 8.88,
            },
            spaceapi::Contact {
                irc: Optional::Absent,
                twitter: Optional::Absent,
                foursquare: Optional::Absent,
                email: Optional::Value("hi@example.com".to_string()),
            },
            vec![
                "email".to_string(),
                "twitter".to_string(),
            ],
        );

        // Add sensor data, build JSON
        let people_present = Some(23);
        let temperature = Some(42.5);
        build_response_json(status, people_present, temperature)
    }

    #[test]
    /// Verify that the result is a JSON object.
    fn verify_json_obj() {
        let json = get_test_data();
        assert!(json.is_object());
    }

    #[test]
    /// Verify that the result has the correct keys.
    fn verify_json_keys() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>
        let keys: Vec<String> = status.keys().cloned().collect();  // Collect the keys
        assert_eq!(keys, ["api", "contact", "issue_report_channels", "location",
                          "logo", "sensors", "space", "state", "url"]);
    }

    #[test]
    /// Verify static data
    fn verify_json_static_data() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>

        // Strings
        assert_eq!(status.get("api").unwrap().as_string().unwrap(), "0.13");
        assert_eq!(status.get("space").unwrap().as_string().unwrap(), "ourspace");
        assert_eq!(status.get("url").unwrap().as_string().unwrap(), "https://example.com/");
        assert_eq!(status.get("logo").unwrap().as_string().unwrap(), "https://example.com/logo.png");

        // Channels
        let channels: &Vec<Json> = status.get("issue_report_channels").unwrap().as_array().unwrap();
        let channel_values: Vec<String> = channels.iter()
                                                  .cloned()
                                                  .map(|c| c.as_string().unwrap().to_string())
                                                  .collect();
        assert_eq!(vec!["email", "twitter"], channel_values);
    }

    #[test]
    /// Verify location
    fn verify_json_location() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let location = status.get("location").unwrap().as_object().unwrap();

        // Verify data
        let address = location.get("address").unwrap().as_string().unwrap();
        assert_eq!("Street 1, Zürich, Switzerland".to_string(), address);
        assert_eq!(47.123, location.get("lat").unwrap().as_f64().unwrap());
        assert_eq!(8.88, location.get("lon").unwrap().as_f64().unwrap());
    }

    #[test]
    /// Verify contact
    fn verify_json_contact() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let contact = status.get("contact").unwrap().as_object().unwrap();

        // Verify data
        let email = contact.get("email").unwrap().as_string().unwrap();
        assert_eq!("hi@example.com".to_string(), email);
    }

    #[test]
    /// Verify sensor data
    fn verify_json_sensors() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let sensors = status.get("sensors").unwrap().as_object().unwrap();
        let temperature_sensor = sensors.get("temperature").unwrap()
                                        .as_array().unwrap()[0]  // List of sensors
                                        .as_object().unwrap();  // Sensor object
        let people_sensor = sensors.get("people_now_present").unwrap()  // List of sensors
                                        .as_array().unwrap()[0]  // Sensor object
                                        .as_object().unwrap();

        // Verify temperature sensor
        let temp_location = temperature_sensor.get("location").unwrap().as_string().unwrap();
        let temp_name = temperature_sensor.get("name").unwrap().as_string().unwrap();
        let temp_unit = temperature_sensor.get("unit").unwrap().as_string().unwrap();
        let temp_value = temperature_sensor.get("value").unwrap().as_f64().unwrap();
        assert_eq!("Basement".to_string(), temp_location);
        assert_eq!("Raspberry CPU".to_string(), temp_name);
        assert_eq!("°C".to_string(), temp_unit);
        assert_eq!(42.5, temp_value);

        // Verify peoplesensor
        let people_location = people_sensor.get("location").unwrap().as_string().unwrap();
        let people_value = people_sensor.get("value").unwrap().as_u64().unwrap();
        assert_eq!("Hackerspace".to_string(), people_location);
        assert_eq!(23, people_value);
    }

}
<commit_msg>server: Print full URL on serve()<commit_after>//! The main entry point for the Space API server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate iron;
extern crate spaceapi;

pub mod datastore;
pub mod redis_store;

use std::net::Ipv4Addr;
use std::sync::Mutex;
use std::sync::Arc;

use rustc_serialize::json::{Json, ToJson};
use iron::{Request, Response, IronResult, Iron, Set};
use iron::{status, headers, middleware};
use iron::modifiers::Header;

pub use datastore::DataStore;
use spaceapi::Optional::{Value, Absent};

fn build_response_json(status: &spaceapi::Status, people_present: Option<u32>, raspi_temperature: Option<f32>) -> Json {
    let people_present_sensor = match people_present {
        Some(count) => Value(vec![
            spaceapi::PeopleNowPresentSensor {
                value: count,
                location: Value("Hackerspace".to_string()),
                name: Absent,
                description: Absent,
                names: Absent,
            }
        ]),
        None => Absent,
    };

    let temperature_sensor = match raspi_temperature {
        Some(degrees) => Value(vec![
            spaceapi::TemperatureSensor {
                value: degrees,
                unit: "°C".to_string(),
                location: "Basement".to_string(),
                name: Value("Raspberry CPU".to_string()),
                description: Absent,
            }
        ]),
        None => Absent,
    };

    // Create a mutable copy of the status struct and add sensor data.
    let mut status_copy = (*status).clone();
    status_copy.sensors = Value(spaceapi::Sensors {
        people_now_present: people_present_sensor,
        temperature: temperature_sensor,
    });

    // Serialize to JSON
    status_copy.to_json()
}

/// A Space API server instance.
///
/// You can create a new instance using the ``new`` constructor method by
/// passing it the host, the port, the ``Status`` object and a datastore.
///
/// The ``SpaceapiServer`` includes a web server through
/// [Hyper](http://hyper.rs/hyper/hyper/server/index.html). Simply call the ``serve`` method.
pub struct SpaceapiServer {
    host: Ipv4Addr,
    port: u16,
    status: spaceapi::Status,
    datastore: Arc<Mutex<Box<DataStore>>>,
}

impl SpaceapiServer {

    pub fn new(host: Ipv4Addr, port: u16, status: spaceapi::Status, datastore: Arc<Mutex<Box<DataStore>>>) -> SpaceapiServer{
        SpaceapiServer {
            host: host,
            port: port,
            status: status,
            datastore: datastore,
        }
    }

    pub fn serve(self) {
        let host = self.host;
        let port = self.port;
        println!("Starting HTTP server on http://{}:{}...", host, port);
        Iron::new(self).http((host, port)).unwrap();
    }

}

impl middleware::Handler for SpaceapiServer {

    fn handle(&self, _: &mut Request) -> IronResult<Response> {

        // Fetch data from datastore
        let datastore_clone = self.datastore.clone();
        let datastore_lock = datastore_clone.lock().unwrap();
        let people_present: Option<u32> = match datastore_lock.retrieve("people_present") {
            Ok(v) => match v.parse::<u32>() {
                Ok(i) => Some(i),
                Err(_) => None,
            },
            Err(_) => None,
        };
        let raspi_temperature: Option<f32> = match datastore_lock.retrieve("raspi_temperature") {
            Ok(v) => match v.parse::<f32>() {
                Ok(i) => Some(i),
                Err(_) => None,
            },
            Err(_) => None,
        };

        // Get response body
        let body = build_response_json(&self.status, people_present, raspi_temperature).to_string();

        // Create response
        let mut response = Response::with((status::Ok, body));

        // Set headers
        response.set_mut(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())));
        response.set_mut(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])));
        response.set_mut(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }
}

#[cfg(test)]
mod test {
    extern crate spaceapi;
    extern crate rustc_serialize;

    use super::build_response_json;
    use spaceapi::Optional;
    use rustc_serialize::json::Json;

    fn get_test_data() -> Json {
        // Create minimal status object
        let ref status = spaceapi::Status::new(
            "ourspace".to_string(),
            "https://example.com/logo.png".to_string(),
            "https://example.com/".to_string(),
            spaceapi::Location {
                address: Optional::Value("Street 1, Zürich, Switzerland".to_string()),
                lat: 47.123,
                lon: 8.88,
            },
            spaceapi::Contact {
                irc: Optional::Absent,
                twitter: Optional::Absent,
                foursquare: Optional::Absent,
                email: Optional::Value("hi@example.com".to_string()),
            },
            vec![
                "email".to_string(),
                "twitter".to_string(),
            ],
        );

        // Add sensor data, build JSON
        let people_present = Some(23);
        let temperature = Some(42.5);
        build_response_json(status, people_present, temperature)
    }

    #[test]
    /// Verify that the result is a JSON object.
    fn verify_json_obj() {
        let json = get_test_data();
        assert!(json.is_object());
    }

    #[test]
    /// Verify that the result has the correct keys.
    fn verify_json_keys() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>
        let keys: Vec<String> = status.keys().cloned().collect();  // Collect the keys
        assert_eq!(keys, ["api", "contact", "issue_report_channels", "location",
                          "logo", "sensors", "space", "state", "url"]);
    }

    #[test]
    /// Verify static data
    fn verify_json_static_data() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>

        // Strings
        assert_eq!(status.get("api").unwrap().as_string().unwrap(), "0.13");
        assert_eq!(status.get("space").unwrap().as_string().unwrap(), "ourspace");
        assert_eq!(status.get("url").unwrap().as_string().unwrap(), "https://example.com/");
        assert_eq!(status.get("logo").unwrap().as_string().unwrap(), "https://example.com/logo.png");

        // Channels
        let channels: &Vec<Json> = status.get("issue_report_channels").unwrap().as_array().unwrap();
        let channel_values: Vec<String> = channels.iter()
                                                  .cloned()
                                                  .map(|c| c.as_string().unwrap().to_string())
                                                  .collect();
        assert_eq!(vec!["email", "twitter"], channel_values);
    }

    #[test]
    /// Verify location
    fn verify_json_location() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let location = status.get("location").unwrap().as_object().unwrap();

        // Verify data
        let address = location.get("address").unwrap().as_string().unwrap();
        assert_eq!("Street 1, Zürich, Switzerland".to_string(), address);
        assert_eq!(47.123, location.get("lat").unwrap().as_f64().unwrap());
        assert_eq!(8.88, location.get("lon").unwrap().as_f64().unwrap());
    }

    #[test]
    /// Verify contact
    fn verify_json_contact() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let contact = status.get("contact").unwrap().as_object().unwrap();

        // Verify data
        let email = contact.get("email").unwrap().as_string().unwrap();
        assert_eq!("hi@example.com".to_string(), email);
    }

    #[test]
    /// Verify sensor data
    fn verify_json_sensors() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let sensors = status.get("sensors").unwrap().as_object().unwrap();
        let temperature_sensor = sensors.get("temperature").unwrap()
                                        .as_array().unwrap()[0]  // List of sensors
                                        .as_object().unwrap();  // Sensor object
        let people_sensor = sensors.get("people_now_present").unwrap()  // List of sensors
                                        .as_array().unwrap()[0]  // Sensor object
                                        .as_object().unwrap();

        // Verify temperature sensor
        let temp_location = temperature_sensor.get("location").unwrap().as_string().unwrap();
        let temp_name = temperature_sensor.get("name").unwrap().as_string().unwrap();
        let temp_unit = temperature_sensor.get("unit").unwrap().as_string().unwrap();
        let temp_value = temperature_sensor.get("value").unwrap().as_f64().unwrap();
        assert_eq!("Basement".to_string(), temp_location);
        assert_eq!("Raspberry CPU".to_string(), temp_name);
        assert_eq!("°C".to_string(), temp_unit);
        assert_eq!(42.5, temp_value);

        // Verify peoplesensor
        let people_location = people_sensor.get("location").unwrap().as_string().unwrap();
        let people_value = people_sensor.get("value").unwrap().as_u64().unwrap();
        assert_eq!("Hackerspace".to_string(), people_location);
        assert_eq!(23, people_value);
    }

}
<|endoftext|>


<commit_before>extern crate libc;

use std::ffi::CString;
use std::mem::transmute;

#[link(name = "rust")]
extern {
  fn klee_make_symbolic(data: *const libc::c_void, length: usize, name: *const libc::c_char);
}

pub fn any(data: *const libc::c_void, length: usize, name: &str) {
  let name_cstr = CString::new(name).unwrap();
  unsafe {
    klee_make_symbolic(data, length, name_cstr.as_ptr());
  }
}

pub fn i32(data: *const i32, length: usize, name: &str) {
  let name_cstr = CString::new(name).unwrap();
  unsafe {
    klee_make_symbolic(transmute(data), length, name_cstr.as_ptr());
  }
}

pub fn u32(data: *const u32, length: usize, name: &str) {
  let name_cstr = CString::new(name).unwrap();
  unsafe {
    klee_make_symbolic(transmute(data), length, name_cstr.as_ptr());
  }
}
<commit_msg>Update lib.rs<commit_after>use std::libc;

use std::ffi::CString;
use std::mem::transmute;

#[link(name = "rust")]
extern {
  fn klee_make_symbolic(data: *const libc::c_void, length: usize, name: *const libc::c_char);
}

pub fn any(data: *const libc::c_void, length: usize, name: &str) {
  let name_cstr = CString::new(name).unwrap();
  unsafe {
    klee_make_symbolic(data, length, name_cstr.as_ptr());
  }
}

pub fn i32(data: *const i32, length: usize, name: &str) {
  let name_cstr = CString::new(name).unwrap();
  unsafe {
    klee_make_symbolic(transmute(data), length, name_cstr.as_ptr());
  }
}

pub fn u32(data: *const u32, length: usize, name: &str) {
  let name_cstr = CString::new(name).unwrap();
  unsafe {
    klee_make_symbolic(transmute(data), length, name_cstr.as_ptr());
  }
}
<|endoftext|>


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

#![feature(collections,std_misc)]

use std::ascii::AsciiExt;
use std::default::Default;

use tokenizer::{PeekableTokens, Token, Tokens};
use types::GeometryCollection;
use types::LineString;
use types::Point;
use types::Polygon;
use types::MultiPoint;
use types::MultiLineString;
use types::MultiPolygon;

mod tokenizer;
mod towkt;
pub mod types;

pub use towkt::ToWkt;

pub enum Geometry {
    Point(Point),
    LineString(LineString),
    Polygon(Polygon),
    MultiPoint(MultiPoint),
    MultiLineString(MultiLineString),
    MultiPolygon(MultiPolygon),
    GeometryCollection(GeometryCollection),
}

impl Geometry {
    fn from_word_and_tokens(word: &str, tokens: &mut PeekableTokens)-> Result<Self, &'static str> {
        match word {
            "POINT" => {
                let x = <Point as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "LINESTRING" => {
                let x = <LineString as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "POLYGON" => {
                let x = <Polygon as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "MULTIPOINT" => {
                let x = <MultiPoint as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "MULTILINESTRING" => {
                let x = <MultiLineString as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "MULTIPOLYGON" => {
                let x = <MultiPolygon as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "GEOMETRYCOLLECTION" => {
                let x = <GeometryCollection as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            _ => Err("Invalid type encountered"),
        }
    }
}
pub struct Wkt {
    pub items: Vec<Geometry>
}

impl Wkt {
    fn new() -> Self {
        Wkt {items: vec![]}
    }

    fn add_item(&mut self, item: Geometry) {
        self.items.push(item);
    }

    fn from_str(wkt_str: &str) -> Result<Self, &'static str> {
        let tokens = Tokens::from_str(wkt_str);
        Wkt::from_tokens(tokens)
    }

    fn from_tokens(tokens: Tokens) -> Result<Self, &'static str> {
        let mut wkt = Wkt::new();
        let mut tokens = tokens.peekable();
        let word = match tokens.next() {
            Some(Token::Word(word)) => {
                if !word.is_ascii() {
                    return Err("Encountered non-ascii word");
                }
                word.to_ascii_uppercase()
            },
            None => return Ok(wkt),
            _ => return Err("Invalid WKT format"),
        };
        match Geometry::from_word_and_tokens(&word, &mut tokens) {
            Ok(item) => wkt.add_item(item),
            Err(s) => return Err(s),
        }
        Ok(wkt)
    }
}

trait FromTokens: Sized+Default {
    fn from_tokens(tokens: &mut PeekableTokens) -> Result<Self, &'static str>;

    fn from_tokens_with_parens(tokens: &mut PeekableTokens) -> Result<Self, &'static str> {
        match tokens.next() {
            Some(Token::ParenOpen) => (),
            Some(Token::Word(ref s)) if s.to_ascii_uppercase() == "EMPTY" =>
                return Ok(Default::default()),
            _ => return Err("Missing open parenthesis for type"),
        };
        let result = FromTokens::from_tokens(tokens);
        match tokens.next() {
            Some(Token::ParenClose) => (),
            _ => return Err("Missing closing parenthesis for type"),
        };
        result
    }

    fn comma_many<F>(f: F, tokens: &mut PeekableTokens) -> Result<Vec<Self>, &'static str>
            where F: Fn(&mut PeekableTokens) -> Result<Self, &'static str> {
        let mut items = Vec::new();

        let item = try!(f(tokens));
        items.push(item);

        while let Some(&Token::Comma) = tokens.peek() {
            tokens.next();  // throw away comma

            let item = try!(f(tokens));
            items.push(item);
        }

        Ok(items)
    }
}

#[cfg(test)]
mod tests {
    use {Wkt, Geometry};
    use types::{MultiPolygon, Point};

    #[test]
    fn empty_string() {
        let wkt = Wkt::from_str("").ok().unwrap();
        assert_eq!(0, wkt.items.len());
    }

    #[test]
    fn empty_items() {
        let mut wkt = Wkt::from_str("POINT EMPTY").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        match wkt.items.pop().unwrap() {
            Geometry::Point(Point(None)) => (),
            _ => unreachable!(),
        };

        let mut wkt = Wkt::from_str("MULTIPOLYGON EMPTY").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        match wkt.items.pop().unwrap() {
            Geometry::MultiPolygon(MultiPolygon(polygons)) =>
                assert_eq!(polygons.len(), 0),
            _ => unreachable!(),
        };
    }
}
<commit_msg>Remove now-stable feature std_misc<commit_after>// Copyright 2014-2015 The GeoRust Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(collections)]

use std::ascii::AsciiExt;
use std::default::Default;

use tokenizer::{PeekableTokens, Token, Tokens};
use types::GeometryCollection;
use types::LineString;
use types::Point;
use types::Polygon;
use types::MultiPoint;
use types::MultiLineString;
use types::MultiPolygon;

mod tokenizer;
mod towkt;
pub mod types;

pub use towkt::ToWkt;

pub enum Geometry {
    Point(Point),
    LineString(LineString),
    Polygon(Polygon),
    MultiPoint(MultiPoint),
    MultiLineString(MultiLineString),
    MultiPolygon(MultiPolygon),
    GeometryCollection(GeometryCollection),
}

impl Geometry {
    fn from_word_and_tokens(word: &str, tokens: &mut PeekableTokens)-> Result<Self, &'static str> {
        match word {
            "POINT" => {
                let x = <Point as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "LINESTRING" => {
                let x = <LineString as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "POLYGON" => {
                let x = <Polygon as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "MULTIPOINT" => {
                let x = <MultiPoint as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "MULTILINESTRING" => {
                let x = <MultiLineString as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "MULTIPOLYGON" => {
                let x = <MultiPolygon as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "GEOMETRYCOLLECTION" => {
                let x = <GeometryCollection as FromTokens>::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            _ => Err("Invalid type encountered"),
        }
    }
}
pub struct Wkt {
    pub items: Vec<Geometry>
}

impl Wkt {
    fn new() -> Self {
        Wkt {items: vec![]}
    }

    fn add_item(&mut self, item: Geometry) {
        self.items.push(item);
    }

    fn from_str(wkt_str: &str) -> Result<Self, &'static str> {
        let tokens = Tokens::from_str(wkt_str);
        Wkt::from_tokens(tokens)
    }

    fn from_tokens(tokens: Tokens) -> Result<Self, &'static str> {
        let mut wkt = Wkt::new();
        let mut tokens = tokens.peekable();
        let word = match tokens.next() {
            Some(Token::Word(word)) => {
                if !word.is_ascii() {
                    return Err("Encountered non-ascii word");
                }
                word.to_ascii_uppercase()
            },
            None => return Ok(wkt),
            _ => return Err("Invalid WKT format"),
        };
        match Geometry::from_word_and_tokens(&word, &mut tokens) {
            Ok(item) => wkt.add_item(item),
            Err(s) => return Err(s),
        }
        Ok(wkt)
    }
}

trait FromTokens: Sized+Default {
    fn from_tokens(tokens: &mut PeekableTokens) -> Result<Self, &'static str>;

    fn from_tokens_with_parens(tokens: &mut PeekableTokens) -> Result<Self, &'static str> {
        match tokens.next() {
            Some(Token::ParenOpen) => (),
            Some(Token::Word(ref s)) if s.to_ascii_uppercase() == "EMPTY" =>
                return Ok(Default::default()),
            _ => return Err("Missing open parenthesis for type"),
        };
        let result = FromTokens::from_tokens(tokens);
        match tokens.next() {
            Some(Token::ParenClose) => (),
            _ => return Err("Missing closing parenthesis for type"),
        };
        result
    }

    fn comma_many<F>(f: F, tokens: &mut PeekableTokens) -> Result<Vec<Self>, &'static str>
            where F: Fn(&mut PeekableTokens) -> Result<Self, &'static str> {
        let mut items = Vec::new();

        let item = try!(f(tokens));
        items.push(item);

        while let Some(&Token::Comma) = tokens.peek() {
            tokens.next();  // throw away comma

            let item = try!(f(tokens));
            items.push(item);
        }

        Ok(items)
    }
}

#[cfg(test)]
mod tests {
    use {Wkt, Geometry};
    use types::{MultiPolygon, Point};

    #[test]
    fn empty_string() {
        let wkt = Wkt::from_str("").ok().unwrap();
        assert_eq!(0, wkt.items.len());
    }

    #[test]
    fn empty_items() {
        let mut wkt = Wkt::from_str("POINT EMPTY").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        match wkt.items.pop().unwrap() {
            Geometry::Point(Point(None)) => (),
            _ => unreachable!(),
        };

        let mut wkt = Wkt::from_str("MULTIPOLYGON EMPTY").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        match wkt.items.pop().unwrap() {
            Geometry::MultiPolygon(MultiPolygon(polygons)) =>
                assert_eq!(polygons.len(), 0),
            _ => unreachable!(),
        };
    }
}
<|endoftext|>


<commit_before>use std::io::IoResult;

/// A wrapper around any struct implementing the `Reader` trait, additionally
/// allowing for `peek` operations to be performed. Therefore, the
/// `PeekableReader` struct also implements the `Reader` trait.
///
/// The primary invariant of the `PeekableReader` is that after calling the
/// `peek` method, the next `read_byte` call will return the same result as
/// the `peek` does. When the result is a byte (read off the wrapped reader),
/// any read-type method of the `Reader` trait will include the byte as the
/// first one. On the other hand, if the result is an `IoError`, the error
/// will be returned regardless of which read-type method of the `Reader` is
/// invoked. Consecutive `peek`s before any read-type operation is used
/// always return the same `IoResult`.
pub struct PeekableReader<R> {
    inner: R,
    peeked_result: Option<IoResult<u8>>,
}

impl<R: Reader> PeekableReader<R> {
    /// Initializes a new `PeekableReader` which wraps the given underlying
    /// reader.
    pub fn new(reader: R) -> PeekableReader<R> {
        PeekableReader {
            inner: reader,
            peeked_result: None,
        }
    }

    /// Returns the `IoResult` which the Reader will return on the next
    /// `get_byte` call.
    ///
    /// If the `IoResult` is indeed an `IoError`, the error will be returned
    /// for any subsequent read operation invoked upon the `Reader`.
    pub fn peek_byte(&mut self) -> IoResult<u8> {
        // Return either the currently cached peeked byte or obtain a new one
        // from the underlying reader.
        match self.peeked_result {
            Some(ref old_res) => old_res.clone(),
            None => {
                // First get the result of the read from the underlying reader
                self.peeked_result = Some(self.inner.read_byte());

                // Now just return that
                self.peeked_result.clone().unwrap()
            }
        }
    }
}

impl<R: Reader> Reader for PeekableReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        if buf.len() == 0 {
            return Ok(0);
        }

        // First, put the byte that was read off the underlying reader in a
        // (possible) previous peek operation (if such a byte is indeed cached)
        let offset = match self.peeked_result.clone() {
            Some(Err(e)) => {
                self.peeked_result = None;
                return Err(e);
            },
            Some(Ok(b)) => {
                buf[0] = b;
                self.peeked_result = None;
                1
            },
            None => 0,
        };

        if offset == 1 && buf.len() == 1 {
            // We've filled the buffer by using the previously peeked byte
            Ok(1)
        } else {
            // We are still missing more bytes, so we read them from the
            // underlying reader and place them directly in the correct place
            // in the buffer.
            let (_, leftover) = buf.split_at_mut(offset);
            Ok(try!(self.inner.read(leftover)) + offset)
        }
    }
}

mod tests {
    use super::PeekableReader;
    use std::io::{MemReader, IoError, IoErrorKind, IoResult};

    /// A mock implementation of the `Reader` trait that returns a given
    /// IoError after a certain number of bytes has been read. The error is
    /// returned only once, with subsequent read calls completing successfully
    /// again.
    /// When the Reader successfully reads a byte, it is always `0u8`.
    struct MockReaderWithError {
        error: IoError,
        after: uint,
        bytes_read: uint,
        errored: bool,
    }

    impl MockReaderWithError {
        fn new(error: IoError, after: uint) -> MockReaderWithError {
            MockReaderWithError {
                error: error,
                after: after,
                bytes_read: 0,
                errored: false,
            }
        }
    }

    impl Reader for MockReaderWithError {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            self.bytes_read += buf.len();
            if self.bytes_read <= self.after || self.errored {
                for b in buf.iter_mut() {
                    *b = 0;
                }

                Ok(buf.len())
            } else {
                self.errored = true;
                Err(self.error.clone())
            }
        }
    }

    /// Helper function which checks whether the given result indicated EOF.
    fn is_eof<T>(res: IoResult<T>) -> bool {
        match res {
            Err(IoError {
                kind: IoErrorKind::EndOfFile,
                ..
            }) => true,
            _ => false,
        }
    }

    /// Helper function which just checks whether the given IoResult is equal
    /// to the given IoError.
    fn is_err<T>(err: &IoError, res: IoResult<T>) -> bool {
        match res {
            Err(ref result_error) => result_error == err,
            _ => false,
        }
    }

    /// Tests that it is possible to invoke the `peek_byte` method multiple
    /// times with the same effect, when there are no intermediate reads.
    #[test]
    fn multiple_peeks_idempotent() {
        let b = 1;
        let mut reader = PeekableReader::new(MemReader::new(vec!(b, b + 1)));

        // The first peek is correct?
        assert_eq!(b, reader.peek_byte().unwrap());
        // The second peek (with no reads in between) still returns the same
        // byte?
        assert_eq!(b, reader.peek_byte().unwrap());
    }

    /// Tests that the `peek_byte` method correctly returns an IoError
    /// returned by the underlying reader on consecutive peek_byte calls.
    #[test]
    fn peek_result_error() {
        let err = IoError {
            kind: IoErrorKind::OtherIoError,
            desc: "Dummy error",
            detail: None,
        };
        let mut reader = PeekableReader::new(
            MockReaderWithError::new(err.clone(), 0));

        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError!");
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the second peek too!");
    }

    /// Tests that performing multiple `peek_byte` calls after the `Reader`
    /// has reached EOF always returns EOF.
    #[test]
    fn multiple_peeks_at_eof() {
        let mut reader = PeekableReader::new(MemReader::new(vec!(1)));
        // Read/skip the first byte
        let _ = reader.read_byte();
        // Consume the EOF (and perform a sanity check that we have reached it)
        assert!(is_eof(reader.read_byte()));

        // All subsequent peeks return EOF
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.peek_byte()));
    }

    /// Tests that peeks and reads correctly work when the underlying reader
    /// only has a single byte.
    #[test]
    fn single_byte_reader_peek() {
        let b = 5u8;
        let mut reader = PeekableReader::new(MemReader::new(vec!(b)));

        // When we peek, we get the correct byte back?
        assert_eq!(b, reader.peek_byte().unwrap());
        // And now we also read it...
        assert_eq!(b, reader.read_byte().unwrap());
        // After this, both the peek and the read return an EOF?
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that peeks and reads from an empty underlying reader instantly
    /// return EOF.
    #[test]
    fn empty_underlying_reader() {
        let mut reader = PeekableReader::new(MemReader::new(vec!()));

        // Must return EOF since the underlying reader is empty
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that when we peek before every read, we correctly end up reading
    /// the entire contents of the underlying Reader.
    #[test]
    fn peek_read_alternate() {
        let vec: Vec<u8> = range(0u8, 5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));

        for &b in vec.iter() {
            assert_eq!(b, reader.peek_byte().unwrap());
            assert_eq!(b, reader.read_byte().unwrap());
        }
        // Now we're at EOF
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that a peek after the underlying reader has reached EOF fails
    /// with an appropriate error.
    #[test]
    fn peek_after_eof() {
        let mut reader = PeekableReader::new(MemReader::new(vec!(1)));
        // Read both the only byte from the reader and the EOF
        let _ = reader.read_byte();
        assert!(is_eof(reader.read_byte()));

        // Now the peek still correctly returns the EOF
        assert!(is_eof(reader.peek_byte()));
    }

    /// Tests that the PeekableReader behaves correctly when only Reader methods
    /// are used.
    #[test]
    fn sequential_reader() {
        let vec: Vec<u8> = range(0u8, 5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));

        for &b in vec.iter() {
            assert_eq!(b, reader.read_byte().unwrap());
        }
        // Now we're at EOF
        assert!(is_eof(reader.read_byte()));
        // Still EOF...
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that a currently cached peeked byte does not get invalidated when
    /// the read method is invoked with an empty buffer.
    #[test]
    fn zero_length_buffer_read_does_not_invalidate_peek() {
        let vec: Vec<u8> = range(0u8, 5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));
        let first_peek = reader.peek_byte().unwrap();

        let mut buffer = vec!();
        let _ = reader.read(buffer.as_mut_slice());

        assert_eq!(first_peek, reader.peek_byte().unwrap());
    }

    /// Tests that when the underlying `Reader` returns an IoError, the `peek`
    /// method keeps returning the same error for each call until the error is
    /// actually "read" by the client (by invoking one of the read methods of
    /// the `Reader`).
    #[test]
    fn always_returns_same_io_error_on_peek() {
        let err = IoError {
            kind: IoErrorKind::OtherIoError,
            desc: "Dummy error",
            detail: None,
        };
        let mut reader = PeekableReader::new(
            MockReaderWithError::new(err.clone(), 1));
        // Read the first byte (no error)
        assert_eq!(0, reader.read_byte().unwrap());

        // This peek now signals an IoError
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the first peek");
        // The next peek still reports the same error...
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the second peek too");
        // The read also indicates the same error.
        assert!(is_err(&err, reader.read_byte()),
                "Expected an IoError on the read too");
        // The next peek has to retry the read -- which succeeds
        assert_eq!(0, reader.peek_byte().unwrap());
    }

    /// Test for the MockReaderWithError helper mock class...
    #[test]
    fn mock_sanity_check() {
        {
            let err = IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "Dummy error",
                detail: None,
            };
            let mut reader = MockReaderWithError::new(err.clone(), 1);

            // First byte is not a problem.
            assert_eq!(0, reader.read_byte().unwrap());
            // However, now the read fails...
            assert!(is_err(&err, reader.read_byte()),
                    "Expected an IoError on the read byte");
            // But, already on the next one, we're out of the woods.
            assert_eq!(0, reader.read_byte().unwrap());
        }
        {
            let err = IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "Dummy error",
                detail: None,
            };
            let mut reader = MockReaderWithError::new(err.clone(), 0);

            // The read fails on the first one...
            assert!(is_err(&err, reader.read_byte()),
                    "Expected an IoError on the read byte");
            // ...but now we're good.
            assert_eq!(0, reader.read_byte().unwrap());
        }
    }

}
<commit_msg>Add #[cfg(test)] attribute to tests module<commit_after>use std::io::IoResult;

/// A wrapper around any struct implementing the `Reader` trait, additionally
/// allowing for `peek` operations to be performed. Therefore, the
/// `PeekableReader` struct also implements the `Reader` trait.
///
/// The primary invariant of the `PeekableReader` is that after calling the
/// `peek` method, the next `read_byte` call will return the same result as
/// the `peek` does. When the result is a byte (read off the wrapped reader),
/// any read-type method of the `Reader` trait will include the byte as the
/// first one. On the other hand, if the result is an `IoError`, the error
/// will be returned regardless of which read-type method of the `Reader` is
/// invoked. Consecutive `peek`s before any read-type operation is used
/// always return the same `IoResult`.
pub struct PeekableReader<R> {
    inner: R,
    peeked_result: Option<IoResult<u8>>,
}

impl<R: Reader> PeekableReader<R> {
    /// Initializes a new `PeekableReader` which wraps the given underlying
    /// reader.
    pub fn new(reader: R) -> PeekableReader<R> {
        PeekableReader {
            inner: reader,
            peeked_result: None,
        }
    }

    /// Returns the `IoResult` which the Reader will return on the next
    /// `get_byte` call.
    ///
    /// If the `IoResult` is indeed an `IoError`, the error will be returned
    /// for any subsequent read operation invoked upon the `Reader`.
    pub fn peek_byte(&mut self) -> IoResult<u8> {
        // Return either the currently cached peeked byte or obtain a new one
        // from the underlying reader.
        match self.peeked_result {
            Some(ref old_res) => old_res.clone(),
            None => {
                // First get the result of the read from the underlying reader
                self.peeked_result = Some(self.inner.read_byte());

                // Now just return that
                self.peeked_result.clone().unwrap()
            }
        }
    }
}

impl<R: Reader> Reader for PeekableReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        if buf.len() == 0 {
            return Ok(0);
        }

        // First, put the byte that was read off the underlying reader in a
        // (possible) previous peek operation (if such a byte is indeed cached)
        let offset = match self.peeked_result.clone() {
            Some(Err(e)) => {
                self.peeked_result = None;
                return Err(e);
            },
            Some(Ok(b)) => {
                buf[0] = b;
                self.peeked_result = None;
                1
            },
            None => 0,
        };

        if offset == 1 && buf.len() == 1 {
            // We've filled the buffer by using the previously peeked byte
            Ok(1)
        } else {
            // We are still missing more bytes, so we read them from the
            // underlying reader and place them directly in the correct place
            // in the buffer.
            let (_, leftover) = buf.split_at_mut(offset);
            Ok(try!(self.inner.read(leftover)) + offset)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::PeekableReader;
    use std::io::{MemReader, IoError, IoErrorKind, IoResult};

    /// A mock implementation of the `Reader` trait that returns a given
    /// IoError after a certain number of bytes has been read. The error is
    /// returned only once, with subsequent read calls completing successfully
    /// again.
    /// When the Reader successfully reads a byte, it is always `0u8`.
    struct MockReaderWithError {
        error: IoError,
        after: uint,
        bytes_read: uint,
        errored: bool,
    }

    impl MockReaderWithError {
        fn new(error: IoError, after: uint) -> MockReaderWithError {
            MockReaderWithError {
                error: error,
                after: after,
                bytes_read: 0,
                errored: false,
            }
        }
    }

    impl Reader for MockReaderWithError {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            self.bytes_read += buf.len();
            if self.bytes_read <= self.after || self.errored {
                for b in buf.iter_mut() {
                    *b = 0;
                }

                Ok(buf.len())
            } else {
                self.errored = true;
                Err(self.error.clone())
            }
        }
    }

    /// Helper function which checks whether the given result indicated EOF.
    fn is_eof<T>(res: IoResult<T>) -> bool {
        match res {
            Err(IoError {
                kind: IoErrorKind::EndOfFile,
                ..
            }) => true,
            _ => false,
        }
    }

    /// Helper function which just checks whether the given IoResult is equal
    /// to the given IoError.
    fn is_err<T>(err: &IoError, res: IoResult<T>) -> bool {
        match res {
            Err(ref result_error) => result_error == err,
            _ => false,
        }
    }

    /// Tests that it is possible to invoke the `peek_byte` method multiple
    /// times with the same effect, when there are no intermediate reads.
    #[test]
    fn multiple_peeks_idempotent() {
        let b = 1;
        let mut reader = PeekableReader::new(MemReader::new(vec!(b, b + 1)));

        // The first peek is correct?
        assert_eq!(b, reader.peek_byte().unwrap());
        // The second peek (with no reads in between) still returns the same
        // byte?
        assert_eq!(b, reader.peek_byte().unwrap());
    }

    /// Tests that the `peek_byte` method correctly returns an IoError
    /// returned by the underlying reader on consecutive peek_byte calls.
    #[test]
    fn peek_result_error() {
        let err = IoError {
            kind: IoErrorKind::OtherIoError,
            desc: "Dummy error",
            detail: None,
        };
        let mut reader = PeekableReader::new(
            MockReaderWithError::new(err.clone(), 0));

        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError!");
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the second peek too!");
    }

    /// Tests that performing multiple `peek_byte` calls after the `Reader`
    /// has reached EOF always returns EOF.
    #[test]
    fn multiple_peeks_at_eof() {
        let mut reader = PeekableReader::new(MemReader::new(vec!(1)));
        // Read/skip the first byte
        let _ = reader.read_byte();
        // Consume the EOF (and perform a sanity check that we have reached it)
        assert!(is_eof(reader.read_byte()));

        // All subsequent peeks return EOF
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.peek_byte()));
    }

    /// Tests that peeks and reads correctly work when the underlying reader
    /// only has a single byte.
    #[test]
    fn single_byte_reader_peek() {
        let b = 5u8;
        let mut reader = PeekableReader::new(MemReader::new(vec!(b)));

        // When we peek, we get the correct byte back?
        assert_eq!(b, reader.peek_byte().unwrap());
        // And now we also read it...
        assert_eq!(b, reader.read_byte().unwrap());
        // After this, both the peek and the read return an EOF?
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that peeks and reads from an empty underlying reader instantly
    /// return EOF.
    #[test]
    fn empty_underlying_reader() {
        let mut reader = PeekableReader::new(MemReader::new(vec!()));

        // Must return EOF since the underlying reader is empty
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that when we peek before every read, we correctly end up reading
    /// the entire contents of the underlying Reader.
    #[test]
    fn peek_read_alternate() {
        let vec: Vec<u8> = range(0u8, 5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));

        for &b in vec.iter() {
            assert_eq!(b, reader.peek_byte().unwrap());
            assert_eq!(b, reader.read_byte().unwrap());
        }
        // Now we're at EOF
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that a peek after the underlying reader has reached EOF fails
    /// with an appropriate error.
    #[test]
    fn peek_after_eof() {
        let mut reader = PeekableReader::new(MemReader::new(vec!(1)));
        // Read both the only byte from the reader and the EOF
        let _ = reader.read_byte();
        assert!(is_eof(reader.read_byte()));

        // Now the peek still correctly returns the EOF
        assert!(is_eof(reader.peek_byte()));
    }

    /// Tests that the PeekableReader behaves correctly when only Reader methods
    /// are used.
    #[test]
    fn sequential_reader() {
        let vec: Vec<u8> = range(0u8, 5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));

        for &b in vec.iter() {
            assert_eq!(b, reader.read_byte().unwrap());
        }
        // Now we're at EOF
        assert!(is_eof(reader.read_byte()));
        // Still EOF...
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that a currently cached peeked byte does not get invalidated when
    /// the read method is invoked with an empty buffer.
    #[test]
    fn zero_length_buffer_read_does_not_invalidate_peek() {
        let vec: Vec<u8> = range(0u8, 5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));
        let first_peek = reader.peek_byte().unwrap();

        let mut buffer = vec!();
        let _ = reader.read(buffer.as_mut_slice());

        assert_eq!(first_peek, reader.peek_byte().unwrap());
    }

    /// Tests that when the underlying `Reader` returns an IoError, the `peek`
    /// method keeps returning the same error for each call until the error is
    /// actually "read" by the client (by invoking one of the read methods of
    /// the `Reader`).
    #[test]
    fn always_returns_same_io_error_on_peek() {
        let err = IoError {
            kind: IoErrorKind::OtherIoError,
            desc: "Dummy error",
            detail: None,
        };
        let mut reader = PeekableReader::new(
            MockReaderWithError::new(err.clone(), 1));
        // Read the first byte (no error)
        assert_eq!(0, reader.read_byte().unwrap());

        // This peek now signals an IoError
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the first peek");
        // The next peek still reports the same error...
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the second peek too");
        // The read also indicates the same error.
        assert!(is_err(&err, reader.read_byte()),
                "Expected an IoError on the read too");
        // The next peek has to retry the read -- which succeeds
        assert_eq!(0, reader.peek_byte().unwrap());
    }

    /// Test for the MockReaderWithError helper mock class...
    #[test]
    fn mock_sanity_check() {
        {
            let err = IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "Dummy error",
                detail: None,
            };
            let mut reader = MockReaderWithError::new(err.clone(), 1);

            // First byte is not a problem.
            assert_eq!(0, reader.read_byte().unwrap());
            // However, now the read fails...
            assert!(is_err(&err, reader.read_byte()),
                    "Expected an IoError on the read byte");
            // But, already on the next one, we're out of the woods.
            assert_eq!(0, reader.read_byte().unwrap());
        }
        {
            let err = IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "Dummy error",
                detail: None,
            };
            let mut reader = MockReaderWithError::new(err.clone(), 0);

            // The read fails on the first one...
            assert!(is_err(&err, reader.read_byte()),
                    "Expected an IoError on the read byte");
            // ...but now we're good.
            assert_eq!(0, reader.read_byte().unwrap());
        }
    }

}
<|endoftext|>