<commit_before>use std::fs::File;
use std::io::prelude::Read;
use std::path;
use std::sync;

use liquid_compiler as compiler;
use liquid_error::{Result, ResultLiquidExt, ResultLiquidReplaceExt};
use liquid_interpreter as interpreter;

use super::Template;
use filters;
use partials;
use tags;

/// Storage for partial-templates.
///
/// This is the recommended policy.  See `liquid::partials` for more options.
pub type Partials = partials::EagerCompiler<partials::InMemorySource>;

pub struct ParserBuilder

where
    P: partials::PartialCompiler,
{
    blocks: compiler::PluginRegistry<Box<compiler::ParseBlock>>,
    tags: compiler::PluginRegistry<Box<compiler::ParseTag>>,
    filters: compiler::PluginRegistry<Box<compiler::ParseFilter>>,
    partials: Option
,
}

impl ParserBuilder<Partials> {
    /// Create an empty Liquid parser
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_liquid() -> Self {
        Self::new().liquid()
    }
}

impl
 ParserBuilder

where
    P: partials::PartialCompiler,
{
    /// Create a Liquid parser with built-in Liquid features
    pub fn liquid(self) -> Self {
        self.liquid_tags().liquid_blocks().liquid_filters()
    }

    /// Register built-in Liquid tags
    pub fn liquid_tags(self) -> Self {
        self.tag(tags::AssignTag)
            .tag(tags::BreakTag)
            .tag(tags::ContinueTag)
            .tag(tags::CycleTag)
            .tag(tags::IncludeTag)
            .tag(tags::IncrementTag)
            .tag(tags::DecrementTag)
    }

    /// Register built-in Liquid blocks
    pub fn liquid_blocks(self) -> Self {
        self.block(tags::RawBlock)
            .block(tags::IfBlock)
            .block(tags::UnlessBlock)
            .block(tags::IfChangedBlock)
            .block(tags::ForBlock)
            .block(tags::TableRowBlock)
            .block(tags::CommentBlock)
            .block(tags::CaptureBlock)
            .block(tags::CaseBlock)
    }

    /// Register built-in Liquid filters
    pub fn liquid_filters(self) -> Self {
        self.filter(filters::std::Abs)
            .filter(filters::std::Append)
            .filter(filters::std::AtLeast)
            .filter(filters::std::AtMost)
            .filter(filters::std::Capitalize)
            .filter(filters::std::Ceil)
            .filter(filters::std::Compact)
            .filter(filters::std::Concat)
            .filter(filters::std::Date)
            .filter(filters::std::Default)
            .filter(filters::std::DividedBy)
            .filter(filters::std::Downcase)
            .filter(filters::std::Escape)
            .filter(filters::std::EscapeOnce)
            .filter(filters::std::First)
            .filter(filters::std::Floor)
            .filter(filters::std::Join)
            .filter(filters::std::Last)
            .filter(filters::std::Lstrip)
            .filter(filters::std::Map)
            .filter(filters::std::Minus)
            .filter(filters::std::Modulo)
            .filter(filters::std::NewlineToBr)
            .filter(filters::std::Plus)
            .filter(filters::std::Prepend)
            .filter(filters::std::Remove)
            .filter(filters::std::RemoveFirst)
            .filter(filters::std::Replace)
            .filter(filters::std::ReplaceFirst)
            .filter(filters::std::Reverse)
            .filter(filters::std::Round)
            .filter(filters::std::Rstrip)
            .filter(filters::std::Size)
            .filter(filters::std::Slice)
            .filter(filters::std::Sort)
            .filter(filters::std::SortNatural)
            .filter(filters::std::Split)
            .filter(filters::std::Strip)
            .filter(filters::std::StripHtml)
            .filter(filters::std::StripNewlines)
            .filter(filters::std::Times)
            .filter(filters::std::Truncate)
            .filter(filters::std::TruncateWords)
            .filter(filters::std::Uniq)
            .filter(filters::std::Upcase)
            .filter(filters::std::UrlDecode)
            .filter(filters::std::UrlEncode)
    }

    /// Register non-standard filters
    #[cfg(not(feature = "extra-filters"))]
    pub fn extra_filters(self) -> Self {
        self
    }

    /// Register non-standard filters
    #[cfg(feature = "extra-filters")]
    pub fn extra_filters(self) -> Self {
        self.filter(filters::extra::DateInTz)
            .filter(filters::extra::Pluralize)
    }

    /// Register non-standard filters
    #[cfg(not(feature = "jekyll-filters"))]
    pub fn jekyll_filters(self) -> Self {
        self
    }

    /// Register non-standard filters
    #[cfg(feature = "jekyll-filters")]
    pub fn jekyll_filters(self) -> Self {
        self.filter(filters::jekyll::Slugify)
            .filter(filters::jekyll::Pop)
            .filter(filters::jekyll::Push)
            .filter(filters::jekyll::Shift)
            .filter(filters::jekyll::Unshift)
            .filter(filters::jekyll::ArrayToSentenceString)
    }

    /// Inserts a new custom block into the parser
    pub fn block<B: Into<Box<compiler::ParseBlock>>>(mut self, block: B) -> Self {
        let block = block.into();
        self.blocks.register(block.start_tag(), block);
        self
    }

    /// Inserts a new custom tag into the parser
    pub fn tag<T: Into<Box<compiler::ParseTag>>>(mut self, tag: T) -> Self {
        let tag = tag.into();
        self.tags.register(tag.tag(), tag);
        self
    }

    /// Inserts a new custom filter into the parser
    pub fn filter<F: Into<Box<compiler::ParseFilter>>>(mut self, filter: F) -> Self {
        let filter = filter.into();
        self.filters.register(filter.name(), filter);
        self
    }

    /// Set which partial-templates will be available.
    pub fn partials<N: partials::PartialCompiler>(self, partials: N) -> ParserBuilder<N> {
        let Self {
            blocks,
            tags,
            filters,
            partials: _partials,
        } = self;
        ParserBuilder {
            blocks,
            tags,
            filters,
            partials: Some(partials),
        }
    }

    /// Create a parser
    pub fn build(self) -> Result<Parser> {
        let Self {
            blocks,
            tags,
            filters,
            partials,
        } = self;

        let mut options = compiler::Language::empty();
        options.blocks = blocks;
        options.tags = tags;
        options.filters = filters;
        let options = sync::Arc::new(options);
        let partials = partials
            .map(|p| p.compile(options.clone()))
            .map_or(Ok(None), |r| r.map(Some))?
            .map(|p| p.into());
        let p = Parser { options, partials };
        Ok(p)
    }
}

impl
 Default for ParserBuilder

where
    P: partials::PartialCompiler,
{
    fn default() -> Self {
        Self {
            blocks: Default::default(),
            tags: Default::default(),
            filters: Default::default(),
            partials: Default::default(),
        }
    }
}

#[derive(Default, Clone)]
pub struct Parser {
    options: sync::Arc<compiler::Language>,
    partials: Option<sync::Arc<interpreter::PartialStore + Send + Sync>>,
}

impl Parser {
    pub fn new() -> Self {
        Default::default()
    }

    /// Parses a liquid template, returning a Template object.
    /// # Examples
    ///
    /// ## Minimal Template
    ///
    /// ```
    /// let template = liquid::ParserBuilder::with_liquid()
    ///     .build().unwrap()
    ///     .parse("Liquid!").unwrap();
    ///
    /// let globals = liquid::value::Object::new();
    /// let output = template.render(&globals).unwrap();
    /// assert_eq!(output, "Liquid!".to_string());
    /// ```
    ///
    pub fn parse(&self, text: &str) -> Result<Template> {
        let template = compiler::parse(text, &self.options).map(interpreter::Template::new)?;
        Ok(Template {
            template,
            partials: self.partials.clone(),
        })
    }

    /// Parse a liquid template from a file, returning a `Result<Template, Error>`.
    /// # Examples
    ///
    /// ## Minimal Template
    ///
    /// `template.txt`:
    ///
    /// ```text
    /// "Liquid {{data}}"
    /// ```
    ///
    /// Your rust code:
    ///
    /// ```rust,no_run
    /// let template = liquid::ParserBuilder::with_liquid()
    ///     .build().unwrap()
    ///     .parse_file("path/to/template.txt").unwrap();
    ///
    /// let mut globals = liquid::value::Object::new();
    /// globals.insert("data".into(), liquid::value::Value::scalar(4f64));
    /// let output = template.render(&globals).unwrap();
    /// assert_eq!(output, "Liquid! 4\n".to_string());
    /// ```
    ///
    pub fn parse_file<P: AsRef<path::Path>>(self, file: P) -> Result<Template> {
        self.parse_file_path(file.as_ref())
    }

    fn parse_file_path(self, file: &path::Path) -> Result<Template> {
        let mut f = File::open(file)
            .replace("Cannot open file")
            .context_key("path")
            .value_with(|| file.to_string_lossy().into_owned().into())?;
        let mut buf = String::new();
        f.read_to_string(&mut buf)
            .replace("Cannot read file")
            .context_key("path")
            .value_with(|| file.to_string_lossy().into_owned().into())?;

        self.parse(&buf)
    }
}
<commit_msg>Fixes #345<commit_after>use std::fs::File;
use std::io::prelude::Read;
use std::path;
use std::sync;

use liquid_compiler as compiler;
use liquid_error::{Result, ResultLiquidExt, ResultLiquidReplaceExt};
use liquid_interpreter as interpreter;

use super::Template;
use filters;
use partials;
use tags;

/// Storage for partial-templates.
///
/// This is the recommended policy.  See `liquid::partials` for more options.
pub type Partials = partials::EagerCompiler<partials::InMemorySource>;

pub struct ParserBuilder

where
    P: partials::PartialCompiler,
{
    blocks: compiler::PluginRegistry<Box<compiler::ParseBlock>>,
    tags: compiler::PluginRegistry<Box<compiler::ParseTag>>,
    filters: compiler::PluginRegistry<Box<compiler::ParseFilter>>,
    partials: Option
,
}

impl ParserBuilder<Partials> {
    /// Create an empty Liquid parser
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_liquid() -> Self {
        Self::new().liquid()
    }
}

impl
 ParserBuilder

where
    P: partials::PartialCompiler,
{
    /// Create a Liquid parser with built-in Liquid features
    pub fn liquid(self) -> Self {
        self.liquid_tags().liquid_blocks().liquid_filters()
    }

    /// Register built-in Liquid tags
    pub fn liquid_tags(self) -> Self {
        self.tag(tags::AssignTag)
            .tag(tags::BreakTag)
            .tag(tags::ContinueTag)
            .tag(tags::CycleTag)
            .tag(tags::IncludeTag)
            .tag(tags::IncrementTag)
            .tag(tags::DecrementTag)
    }

    /// Register built-in Liquid blocks
    pub fn liquid_blocks(self) -> Self {
        self.block(tags::RawBlock)
            .block(tags::IfBlock)
            .block(tags::UnlessBlock)
            .block(tags::IfChangedBlock)
            .block(tags::ForBlock)
            .block(tags::TableRowBlock)
            .block(tags::CommentBlock)
            .block(tags::CaptureBlock)
            .block(tags::CaseBlock)
    }

    /// Register built-in Liquid filters
    pub fn liquid_filters(self) -> Self {
        self.filter(filters::std::Abs)
            .filter(filters::std::Append)
            .filter(filters::std::AtLeast)
            .filter(filters::std::AtMost)
            .filter(filters::std::Capitalize)
            .filter(filters::std::Ceil)
            .filter(filters::std::Compact)
            .filter(filters::std::Concat)
            .filter(filters::std::Date)
            .filter(filters::std::Default)
            .filter(filters::std::DividedBy)
            .filter(filters::std::Downcase)
            .filter(filters::std::Escape)
            .filter(filters::std::EscapeOnce)
            .filter(filters::std::First)
            .filter(filters::std::Floor)
            .filter(filters::std::Join)
            .filter(filters::std::Last)
            .filter(filters::std::Lstrip)
            .filter(filters::std::Map)
            .filter(filters::std::Minus)
            .filter(filters::std::Modulo)
            .filter(filters::std::NewlineToBr)
            .filter(filters::std::Plus)
            .filter(filters::std::Prepend)
            .filter(filters::std::Remove)
            .filter(filters::std::RemoveFirst)
            .filter(filters::std::Replace)
            .filter(filters::std::ReplaceFirst)
            .filter(filters::std::Reverse)
            .filter(filters::std::Round)
            .filter(filters::std::Rstrip)
            .filter(filters::std::Size)
            .filter(filters::std::Slice)
            .filter(filters::std::Sort)
            .filter(filters::std::SortNatural)
            .filter(filters::std::Split)
            .filter(filters::std::Strip)
            .filter(filters::std::StripHtml)
            .filter(filters::std::StripNewlines)
            .filter(filters::std::Times)
            .filter(filters::std::Truncate)
            .filter(filters::std::TruncateWords)
            .filter(filters::std::Uniq)
            .filter(filters::std::Upcase)
            .filter(filters::std::UrlDecode)
            .filter(filters::std::UrlEncode)
    }

    /// Register non-standard filters
    #[cfg(not(feature = "extra-filters"))]
    pub fn extra_filters(self) -> Self {
        self
    }

    /// Register non-standard filters
    #[cfg(feature = "extra-filters")]
    pub fn extra_filters(self) -> Self {
        self.filter(filters::extra::DateInTz)
            .filter(filters::extra::Pluralize)
    }

    /// Register non-standard filters
    #[cfg(not(feature = "jekyll-filters"))]
    pub fn jekyll_filters(self) -> Self {
        self
    }

    /// Register non-standard filters
    #[cfg(feature = "jekyll-filters")]
    pub fn jekyll_filters(self) -> Self {
        self.filter(filters::jekyll::Slugify)
            .filter(filters::jekyll::Pop)
            .filter(filters::jekyll::Push)
            .filter(filters::jekyll::Shift)
            .filter(filters::jekyll::Unshift)
            .filter(filters::jekyll::ArrayToSentenceString)
    }

    /// Inserts a new custom block into the parser
    pub fn block<B: Into<Box<compiler::ParseBlock>>>(mut self, block: B) -> Self {
        let block = block.into();
        self.blocks.register(block.start_tag(), block);
        self
    }

    /// Inserts a new custom tag into the parser
    pub fn tag<T: Into<Box<compiler::ParseTag>>>(mut self, tag: T) -> Self {
        let tag = tag.into();
        self.tags.register(tag.tag(), tag);
        self
    }

    /// Inserts a new custom filter into the parser
    pub fn filter<F: Into<Box<compiler::ParseFilter>>>(mut self, filter: F) -> Self {
        let filter = filter.into();
        self.filters.register(filter.name(), filter);
        self
    }

    /// Set which partial-templates will be available.
    pub fn partials<N: partials::PartialCompiler>(self, partials: N) -> ParserBuilder<N> {
        let Self {
            blocks,
            tags,
            filters,
            partials: _partials,
        } = self;
        ParserBuilder {
            blocks,
            tags,
            filters,
            partials: Some(partials),
        }
    }

    /// Create a parser
    pub fn build(self) -> Result<Parser> {
        let Self {
            blocks,
            tags,
            filters,
            partials,
        } = self;

        let mut options = compiler::Language::empty();
        options.blocks = blocks;
        options.tags = tags;
        options.filters = filters;
        let options = sync::Arc::new(options);
        let partials = partials
            .map(|p| p.compile(options.clone()))
            .map_or(Ok(None), |r| r.map(Some))?
            .map(|p| p.into());
        let p = Parser { options, partials };
        Ok(p)
    }
}

impl
 Default for ParserBuilder

where
    P: partials::PartialCompiler,
{
    fn default() -> Self {
        Self {
            blocks: Default::default(),
            tags: Default::default(),
            filters: Default::default(),
            partials: Default::default(),
        }
    }
}

#[derive(Default, Clone)]
pub struct Parser {
    options: sync::Arc<compiler::Language>,
    partials: Option<sync::Arc<interpreter::PartialStore + Send + Sync>>,
}

impl Parser {
    pub fn new() -> Self {
        Default::default()
    }

    /// Parses a liquid template, returning a Template object.
    /// # Examples
    ///
    /// ## Minimal Template
    ///
    /// ```
    /// let template = liquid::ParserBuilder::with_liquid()
    ///     .build().unwrap()
    ///     .parse("Liquid!").unwrap();
    ///
    /// let globals = liquid::value::Object::new();
    /// let output = template.render(&globals).unwrap();
    /// assert_eq!(output, "Liquid!".to_string());
    /// ```
    ///
    pub fn parse(&self, text: &str) -> Result<Template> {
        let template = compiler::parse(text, &self.options).map(interpreter::Template::new)?;
        Ok(Template {
            template,
            partials: self.partials.clone(),
        })
    }

    /// Parse a liquid template from a file, returning a `Result<Template, Error>`.
    /// # Examples
    ///
    /// ## Minimal Template
    ///
    /// `template.txt`:
    ///
    /// ```text
    /// "Liquid {{data}}"
    /// ```
    ///
    /// Your rust code:
    ///
    /// ```rust,no_run
    /// let template = liquid::ParserBuilder::with_liquid()
    ///     .build().unwrap()
    ///     .parse_file("path/to/template.txt").unwrap();
    ///
    /// let mut globals = liquid::value::Object::new();
    /// globals.insert("data".into(), liquid::value::Value::scalar(4f64));
    /// let output = template.render(&globals).unwrap();
    /// assert_eq!(output, "Liquid! 4\n".to_string());
    /// ```
    ///
    pub fn parse_file<P: AsRef<path::Path>>(&self, file: P) -> Result<Template> {
        self.parse_file_path(file.as_ref())
    }

    fn parse_file_path(&self, file: &path::Path) -> Result<Template> {
        let mut f = File::open(file)
            .replace("Cannot open file")
            .context_key("path")
            .value_with(|| file.to_string_lossy().into_owned().into())?;
        let mut buf = String::new();
        f.read_to_string(&mut buf)
            .replace("Cannot read file")
            .context_key("path")
            .value_with(|| file.to_string_lossy().into_owned().into())?;

        self.parse(&buf)
    }
}
<|endoftext|>


<commit_before>//! The parser module implements a nock syntax parser.

use std::str::FromStr;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::error::Error;

use tokenizer::{Tokenizer, Token, TokenizerError, ExpressionReader};

#[derive(Debug,PartialEq)]
pub enum Noun {
    Atom(u64),
    Cell(Box<Noun>, Vec<Noun>),
}

#[derive(Debug)]
pub struct ParseError {
    msg: String,
    cause: Option<Box<Error>>,
}

impl ParseError {
    pub fn new<S: Into<String>>(msg: S) -> Self {
        ParseError {
            msg: msg.into(),
            cause: None,
        }
    }

    pub fn new_with_cause<S: Into<String>>(msg: S, err: Box<Error>) -> Self {
        ParseError {
            msg: msg.into(),
            cause: Some(err),
        }
    }
}

impl Display for ParseError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "ParseError: {}\n", self.msg));
        if let Some(ref cause) = self.cause {
            try!(write!(f, "Cause:\n\t{}", cause));
        }
        return Ok(());
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        &self.msg
    }

    fn cause(&self) -> Option<&Error> {
        if let Some(ref cause) = self.cause {
            return Some(cause.as_ref());
        }
        return None;
    }
}

impl From<TokenizerError> for ParseError {
    fn from(err: TokenizerError) -> Self {
        Self::new_with_cause("Tokenizer Error", Box::new(err))
    }
}

pub struct Parser {
    toker: Tokenizer,
}

impl Parser {
    pub fn new(reader: Box<ExpressionReader>) -> Self {
        Parser { toker: Tokenizer::new(reader) }
    }

    fn parse_atom(&mut self, tok: &Token) -> Result<Noun, ParseError> {
        let atom = u64::from_str(&tok.val);
        return match atom {
            Ok(atom) => Ok(Noun::Atom(atom)),
            Err(e) => Err(ParseError::new_with_cause("Atom ParseError", Box::new(e))),
        }
    }

    fn parse_cell(&mut self) -> Result<Noun, ParseError> {
        let head = try!(self.parse());
        let tail = try!(self.parse());
        Ok(Noun::Cell(Box::new(head), vec![tail]))
    }

    pub fn parse(&mut self) -> Result<Noun, ParseError> {
        let tok = try!(self.toker.next());
        if tok.is_atom() {
            return self.parse_atom(&tok)
        } else if tok.is_cell_start() {
            return self.parse_cell()
        } else if tok.is_cell_end() {
            // FIXME(jwall): What is this state transition?
        }
        Err(ParseError::new("Unhandled Token!"))
    }
}

#[cfg(test)]
mod parser_tests {
    use parser::{Parser, Noun};
    use tokenizer::tokenizer_tests::MockReader;

    #[test]
    fn test_parse_simple_atom() {
        let reader = MockReader::new(vec![
            "1".to_string(),
        ]);
        let mut parser = Parser::new(Box::new(reader));
        let noun = parser.parse();
        assert!(noun.is_ok());
        let noun = noun.unwrap();
        assert_eq!(noun, Noun::Atom(1));
    }

    #[test]
    fn test_parse_simple_cell() {
        let reader = MockReader::new(vec![
            "[1 2]".to_string(),
        ]);
        let mut parser = Parser::new(Box::new(reader));
        let noun = parser.parse();
        assert!(noun.is_ok());
        let noun = noun.unwrap();
        assert_eq!(noun, Noun::Cell(Box::new(Noun::Atom(1)),
                                    vec![Noun::Atom(2)]));
    }

    #[test]
    fn test_parse_consed_cell() {
        let reader = MockReader::new(vec![
            "[1 2 3]".to_string(),
        ]);
        let mut parser = Parser::new(Box::new(reader));
        let noun = parser.parse();
        assert!(noun.is_ok());
        let noun = noun.unwrap();
        assert_eq!(noun, Noun::Cell(Box::new(Noun::Atom(1)),
                                    vec![Noun::Atom(2),
                                         Noun::Atom(3)]));
    }
}
<commit_msg>Parsing for nested expressions.<commit_after>//! The parser module implements a nock syntax parser.

use std::str::FromStr;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::error::Error;

use tokenizer::{Tokenizer, Token, TokenizerError, ExpressionReader};

#[derive(Debug,PartialEq)]
pub enum Noun {
    Atom(u64),
    Cell(Box<Noun>, Vec<Noun>),
}

#[derive(Debug)]
pub struct ParseError {
    msg: String,
    cause: Option<Box<Error>>,
}

impl ParseError {
    pub fn new<S: Into<String>>(msg: S) -> Self {
        ParseError {
            msg: msg.into(),
            cause: None,
        }
    }

    pub fn new_with_cause<S: Into<String>>(msg: S, err: Box<Error>) -> Self {
        ParseError {
            msg: msg.into(),
            cause: Some(err),
        }
    }
}

impl Display for ParseError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "ParseError: {}\n", self.msg));
        if let Some(ref cause) = self.cause {
            try!(write!(f, "Cause:\n\t{}", cause));
        }
        return Ok(());
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        &self.msg
    }

    fn cause(&self) -> Option<&Error> {
        if let Some(ref cause) = self.cause {
            return Some(cause.as_ref());
        }
        return None;
    }
}

impl From<TokenizerError> for ParseError {
    fn from(err: TokenizerError) -> Self {
        Self::new_with_cause("Tokenizer Error", Box::new(err))
    }
}

pub struct Parser {
    toker: Tokenizer,
}

impl Parser {
    pub fn new(reader: Box<ExpressionReader>) -> Self {
        Parser { toker: Tokenizer::new(reader) }
    }

    fn parse_atom(&mut self, tok: &Token) -> Result<Noun, ParseError> {
        let atom = u64::from_str(&tok.val);
        return match atom {
            Ok(atom) => Ok(Noun::Atom(atom)),
            Err(e) => Err(ParseError::new_with_cause("Atom ParseError", Box::new(e))),
        };
    }

    fn flatten(&self, mut nouns: Vec<Noun>) -> Vec<Noun> {
        if nouns.len() == 1 {
            let noun = nouns.pop();
            if let Some(Noun::Cell(head, tail)) = noun {
                nouns.push(*head);
                let mut new_tail = self.flatten(tail);
                nouns.append(&mut new_tail);
            } else if let Some(noun) = noun {
                nouns.push(noun);
            }
        }
        return nouns;
    }

    fn parse_cell(&mut self) -> Result<Noun, ParseError> {
        let head = try!(self.parse());
        let mut tail = Vec::<Noun>::new();
        loop {
            let tok = try!(self.toker.next());
            if tok.is_atom() {
                tail.push(try!(self.parse_atom(&tok)))
            } else if tok.is_cell_start() {
                tail.push(try!(self.parse_cell()))
            } else if tok.is_cell_end() {
                tail = self.flatten(tail);
                break;
            }
        }
        Ok(Noun::Cell(Box::new(head), tail))
    }

    pub fn parse(&mut self) -> Result<Noun, ParseError> {
        let tok = try!(self.toker.next());
        if tok.is_atom() {
            return self.parse_atom(&tok);
        } else if tok.is_cell_start() {
            return self.parse_cell();
        }
        Err(ParseError::new("Unhandled Token!"))
    }
}

#[cfg(test)]
mod parser_tests {
    use parser::{Parser, Noun};
    use tokenizer::tokenizer_tests::MockReader;

    #[test]
    fn test_parse_simple_atom() {
        let reader = MockReader::new(vec![
            "1".to_string(),
        ]);
        let mut parser = Parser::new(Box::new(reader));
        let noun = parser.parse();
        assert!(noun.is_ok());
        let noun = noun.unwrap();
        assert_eq!(noun, Noun::Atom(1));
    }

    #[test]
    fn test_parse_simple_cell() {
        let reader = MockReader::new(vec![
            "[1 2]".to_string(),
        ]);
        let mut parser = Parser::new(Box::new(reader));
        let noun = parser.parse();
        assert!(noun.is_ok());
        let noun = noun.unwrap();
        assert_eq!(noun,
                   Noun::Cell(Box::new(Noun::Atom(1)), vec![Noun::Atom(2)]));
    }

    #[test]
    fn test_parse_autoconsed_cell() {
        let reader = MockReader::new(vec![
            "[1 2 3]".to_string(),
        ]);
        let mut parser = Parser::new(Box::new(reader));
        let noun = parser.parse();
        assert!(noun.is_ok());
        let noun = noun.unwrap();
        assert_eq!(noun,
                   Noun::Cell(Box::new(Noun::Atom(1)), vec![Noun::Atom(2), Noun::Atom(3)]));
    }

    #[test]
    fn test_parse_consed_cell() {
        let reader = MockReader::new(vec![
            "[1 [2 3]]".to_string(),
        ]);
        let mut parser = Parser::new(Box::new(reader));
        let noun = parser.parse();
        assert!(noun.is_ok());
        let noun = noun.unwrap();
        assert_eq!(noun,
                   Noun::Cell(Box::new(Noun::Atom(1)), vec![Noun::Atom(2), Noun::Atom(3)]));
    }

    #[test]
    fn test_parse_nested_cell() {
        let reader = MockReader::new(vec![
            "[1 [2 3] 4]".to_string(),
        ]);
        let mut parser = Parser::new(Box::new(reader));
        let noun = parser.parse();
        assert!(noun.is_ok());
        let noun = noun.unwrap();
        assert_eq!(noun,
                   Noun::Cell(Box::new(Noun::Atom(1)),
                              vec![Noun::Cell(Box::new(Noun::Atom(2)), vec![Noun::Atom(3)]),
                                   Noun::Atom(4)]));
    }
}
<|endoftext|>


<commit_before>// Each of these functions finds the energy of the lowest energy paths going through
// each pixel in a given dimension. We'll do this by accumulating the energy of the
// paths from one side to the other. We can use this to find the paths themselves.

use pixel;
use std;
use vec2d;

// A pixel's energy is the sum in differences in value between it and its neighbors.
fn energy(data: &vec2d::T<pixel::T>) -> vec2d::T<u32> {
  let get = |x, y| {
    if
      x < 0 || x >= data.width  as isize ||
      y < 0 || y >= data.height as isize ||
      false
    {
      None
    } else {
      Some(*data.get(x as usize, y as usize))
    }
  };

  let mut energy = vec2d::new(data.width, data.height, 0);

  for x in 0..data.width as isize {
  for y in 0..data.height as isize {
    let mut accum = 0;

    let cur = get(x, y).unwrap();
    get(x - 1, y    ).map(|neighbor| accum = accum + pixel::diff(cur, neighbor));
    get(x + 1, y    ).map(|neighbor| accum = accum + pixel::diff(cur, neighbor));
    get(x    , y - 1).map(|neighbor| accum = accum + pixel::diff(cur, neighbor));
    get(x    , y + 1).map(|neighbor| accum = accum + pixel::diff(cur, neighbor));

    *energy.get_mut(x as usize, y as usize) = accum;
  }}

  energy
}

fn y_paths(energy: &vec2d::T<u32>) -> vec2d::T<u32> {
  let mut paths = vec2d::new(energy.width, energy.height, 0);
  for x in 0 .. energy.width {
    *paths.get_mut(x, 0) = *energy.get(x, 0);
  }

  // TODO: turn things into filter-maps

  for y in 1 .. energy.height {
    for x in 0 .. energy.width {
      // Minimum energy path to this cell's "ancestor".
      let mut min_ancestor = *paths.get(x, y - 1);
      if x > 0 {
        min_ancestor = std::cmp::min(min_ancestor, *paths.get(x - 1, y - 1));
      }
      if x < paths.width - 1 {
        min_ancestor = std::cmp::min(min_ancestor, *paths.get(x + 1, y - 1));
      }

      *paths.get_mut(x, y) = min_ancestor + energy.get(x, y);
    }
  }

  paths
}

pub fn decrement_width(data: &vec2d::T<pixel::T>) -> vec2d::T<pixel::T> {
  let energy = energy(&data);

  let paths = y_paths(&energy);

  let mut path = vec2d::new(1, paths.height, 0);
  *path.get_mut(0, paths.height - 1) =
    (0 .. paths.width)
    .min_by_key(|&x| *paths.get(x, paths.height - 1))
    .unwrap();
  for y in (0 .. paths.height - 2).rev() {
    let ancestor = *path.get(0, y + 1) as isize;
    let x =
      [ancestor - 1, ancestor, ancestor + 1].iter()
        .filter_map(|&x| {
          if x < 0 || x >= data.width as isize {
            None
          } else {
            Some(x as usize)
          }
        })
        .min_by_key(|&x| *paths.get(x, y))
        .unwrap();
    *path.get_mut(0, y) = x;
  }

  let mut new_data = vec2d::new(data.width - 1, data.height, pixel::empty());
  for y in 0 .. data.height {
    for x in 0 .. data.width {
      match x.cmp(&path.get(0, y)) {
        std::cmp::Ordering::Less    => *new_data.get_mut(x, y) = *data.get(x, y),
        std::cmp::Ordering::Greater => *new_data.get_mut(x - 1, y) = *data.get(x, y),
        std::cmp::Ordering::Equal   => {},
      }
    }
  }

  new_data
}

// pub fn decrement_height<pixel::T>(energy: &vec2d::T<pixel::T>) -> vec2d::T<pixel::T> {
//   let mut paths = vec2d::new(energy.width, energy.height, 0);
//   for x in 0..energy.width {
//     *paths.get_mut(x, 0) = energy.get(x, 0);
//   }
//
//   for y in 1..energy.height {
//     for x in 0..energy.width {
//       // Minimum energy path to this cell's "ancestor".
//       let mut min_to_ancestor = *energy.get(x, y - 1);
//       if x > 0 {
//         min_to_ancestor = std::cmp::min(min_to_ancestor, *energy.get(x - 1, y - 1));
//       }
//       if x < energy.width - 1 {
//         min_to_ancestor = std::cmp::min(min_to_ancestor, *energy.get(x + 1, y - 1));
//       }
//
//       *paths.get_mut(x, y) = min_to_ancestor + energy.get(x, y);
//     }
//   }
// }

pub fn energy_map(data: &vec2d::T<pixel::T>) -> vec2d::T<pixel::T> {
  let energy = energy(&data);

  let max_energy =
    (0 .. energy.width)
    .flat_map(|x| {
      let energy = &energy;
      (0 .. energy.height)
      .map(move |y| {
        *energy.get(x, y)
      })
    })
    .max()
    .unwrap();

  let mut new_data = vec2d::new(data.width, data.height, pixel::empty());
  for y in 0 .. data.height {
    for x in 0 .. data.width {
      let mut data = *data.get(x, y);
      let energy = std::cmp::min(((*energy.get(x, y) as f32 / max_energy as f32) * 255.0) as u32, 255) as u8;
      data.data[0] = energy;
      data.data[1] = energy;
      data.data[2] = energy;
      *new_data.get_mut(x, y) = data;
    }
  }

  new_data
}

pub fn path_energy_map(data: &vec2d::T<pixel::T>) -> vec2d::T<pixel::T> {
  let energy = energy(&data);

  let paths = y_paths(&energy);

  let max_energy =
    (0 .. paths.width)
    .flat_map(|x| {
      let paths = &paths;
      (0 .. paths.height)
      .map(move |y| {
        *paths.get(x, y)
      })
    })
    .max()
    .unwrap();

  let mut new_data = vec2d::new(data.width, data.height, pixel::empty());
  for x in 0 .. data.width {
  for y in 0 .. data.height {
    let mut data = *data.get(x, y);
    let energy = std::cmp::min(((*paths.get(x, y) as f32 / max_energy as f32) * 255.0) as u32, 255) as u8;
    data.data[0] = energy;
    data.data[1] = energy;
    data.data[2] = energy;
    *new_data.get_mut(x, y) = data;
  }}

  new_data
}

pub fn highlight_y_paths(data: &vec2d::T<pixel::T>) -> vec2d::T<pixel::T> {
  let energy = energy(&data);

  let paths = y_paths(&energy);

  let mut path = vec2d::new(1, energy.height, 0);
  *path.get_mut(0, energy.height - 1) =
    (0..energy.width)
    .min_by_key(|&x| *paths.get(x, energy.height - 1))
    .unwrap();
  for y in (0 .. energy.height - 2).rev() {
    let ancestor = *path.get(0, y + 1) as isize;
    let (x, _path_energy) =
      [ancestor - 1, ancestor, ancestor + 1].iter()
        .filter_map(|&x| {
          if x < 0 || x >= data.width as isize {
            None
          } else {
            Some((x as usize, paths.get(x as usize, y)))
          }
        })
        .min_by_key(|&(_x, path_energy)| path_energy)
        .unwrap();
    *path.get_mut(0, y) = x;
  }

  let mut new_data = vec2d::new(data.width, data.height, pixel::empty());
  for y in 0 .. data.height {
    for x in 0 .. data.width {
      match x.cmp(&path.get(0, y)) {
        std::cmp::Ordering::Equal => {
          let mut data = *data.get(x, y);
          data[0] = 255;
          data[1] = 0;
          data[2] = 0;
          *new_data.get_mut(x, y) = data;
        },
        _ => {
          *new_data.get_mut(x, y) = *data.get(x, y);
        },
      }
    }
  }

  new_data
}
<commit_msg>Off-by-one rabble rabble<commit_after>// Each of these functions finds the energy of the lowest energy paths going through
// each pixel in a given dimension. We'll do this by accumulating the energy of the
// paths from one side to the other. We can use this to find the paths themselves.

use pixel;
use std;
use vec2d;

// A pixel's energy is the sum in differences in value between it and its neighbors.
fn energy(data: &vec2d::T<pixel::T>) -> vec2d::T<u32> {
  let get = |x, y| {
    if
      x < 0 || x >= data.width  as isize ||
      y < 0 || y >= data.height as isize ||
      false
    {
      None
    } else {
      Some(*data.get(x as usize, y as usize))
    }
  };

  let mut energy = vec2d::new(data.width, data.height, 0);

  for x in 0..data.width as isize {
  for y in 0..data.height as isize {
    let mut accum = 0;

    let cur = get(x, y).unwrap();
    get(x - 1, y    ).map(|neighbor| accum = accum + pixel::diff(cur, neighbor));
    get(x + 1, y    ).map(|neighbor| accum = accum + pixel::diff(cur, neighbor));
    get(x    , y - 1).map(|neighbor| accum = accum + pixel::diff(cur, neighbor));
    get(x    , y + 1).map(|neighbor| accum = accum + pixel::diff(cur, neighbor));

    *energy.get_mut(x as usize, y as usize) = accum;
  }}

  energy
}

fn y_paths(energy: &vec2d::T<u32>) -> vec2d::T<u32> {
  let mut paths = vec2d::new(energy.width, energy.height, 0);
  for x in 0 .. energy.width {
    *paths.get_mut(x, 0) = *energy.get(x, 0);
  }

  // TODO: turn things into filter-maps

  for y in 1 .. energy.height {
    for x in 0 .. energy.width {
      // Minimum energy path to this cell's "ancestor".
      let mut min_ancestor = *paths.get(x, y - 1);
      if x > 0 {
        min_ancestor = std::cmp::min(min_ancestor, *paths.get(x - 1, y - 1));
      }
      if x < paths.width - 1 {
        min_ancestor = std::cmp::min(min_ancestor, *paths.get(x + 1, y - 1));
      }

      *paths.get_mut(x, y) = min_ancestor + energy.get(x, y);
    }
  }

  paths
}

pub fn decrement_width(data: &vec2d::T<pixel::T>) -> vec2d::T<pixel::T> {
  let energy = energy(&data);

  let paths = y_paths(&energy);

  let mut path = vec2d::new(1, paths.height, 0);
  *path.get_mut(0, paths.height - 1) =
    (0 .. paths.width)
    .min_by_key(|&x| *paths.get(x, paths.height - 1))
    .unwrap();
  for y in (0 .. paths.height - 1).rev() {
    let ancestor = *path.get(0, y + 1) as isize;
    let x =
      [ancestor - 1, ancestor, ancestor + 1].iter()
        .filter_map(|&x| {
          if x < 0 || x >= data.width as isize {
            None
          } else {
            Some(x as usize)
          }
        })
        .min_by_key(|&x| *paths.get(x, y))
        .unwrap();
    *path.get_mut(0, y) = x;
  }

  let mut new_data = vec2d::new(data.width - 1, data.height, pixel::empty());
  for y in 0 .. data.height {
    for x in 0 .. data.width {
      match x.cmp(&path.get(0, y)) {
        std::cmp::Ordering::Less    => *new_data.get_mut(x, y) = *data.get(x, y),
        std::cmp::Ordering::Greater => *new_data.get_mut(x - 1, y) = *data.get(x, y),
        std::cmp::Ordering::Equal   => {},
      }
    }
  }

  new_data
}

// pub fn decrement_height<pixel::T>(energy: &vec2d::T<pixel::T>) -> vec2d::T<pixel::T> {
//   let mut paths = vec2d::new(energy.width, energy.height, 0);
//   for x in 0..energy.width {
//     *paths.get_mut(x, 0) = energy.get(x, 0);
//   }
//
//   for y in 1..energy.height {
//     for x in 0..energy.width {
//       // Minimum energy path to this cell's "ancestor".
//       let mut min_to_ancestor = *energy.get(x, y - 1);
//       if x > 0 {
//         min_to_ancestor = std::cmp::min(min_to_ancestor, *energy.get(x - 1, y - 1));
//       }
//       if x < energy.width - 1 {
//         min_to_ancestor = std::cmp::min(min_to_ancestor, *energy.get(x + 1, y - 1));
//       }
//
//       *paths.get_mut(x, y) = min_to_ancestor + energy.get(x, y);
//     }
//   }
// }

pub fn energy_map(data: &vec2d::T<pixel::T>) -> vec2d::T<pixel::T> {
  let energy = energy(&data);

  let max_energy =
    (0 .. energy.width)
    .flat_map(|x| {
      let energy = &energy;
      (0 .. energy.height)
      .map(move |y| {
        *energy.get(x, y)
      })
    })
    .max()
    .unwrap();

  let mut new_data = vec2d::new(data.width, data.height, pixel::empty());
  for y in 0 .. data.height {
    for x in 0 .. data.width {
      let mut data = *data.get(x, y);
      let energy = std::cmp::min(((*energy.get(x, y) as f32 / max_energy as f32) * 255.0) as u32, 255) as u8;
      data.data[0] = energy;
      data.data[1] = energy;
      data.data[2] = energy;
      *new_data.get_mut(x, y) = data;
    }
  }

  new_data
}

pub fn path_energy_map(data: &vec2d::T<pixel::T>) -> vec2d::T<pixel::T> {
  let energy = energy(&data);

  let paths = y_paths(&energy);

  let max_energy =
    (0 .. paths.width)
    .flat_map(|x| {
      let paths = &paths;
      (0 .. paths.height)
      .map(move |y| {
        *paths.get(x, y)
      })
    })
    .max()
    .unwrap();

  let mut new_data = vec2d::new(data.width, data.height, pixel::empty());
  for x in 0 .. data.width {
  for y in 0 .. data.height {
    let mut data = *data.get(x, y);
    let energy = std::cmp::min(((*paths.get(x, y) as f32 / max_energy as f32) * 255.0) as u32, 255) as u8;
    data.data[0] = energy;
    data.data[1] = energy;
    data.data[2] = energy;
    *new_data.get_mut(x, y) = data;
  }}

  new_data
}

pub fn highlight_y_paths(data: &vec2d::T<pixel::T>) -> vec2d::T<pixel::T> {
  let energy = energy(&data);

  let paths = y_paths(&energy);

  let mut path = vec2d::new(1, energy.height, 0);
  *path.get_mut(0, energy.height - 1) =
    (0..energy.width)
    .min_by_key(|&x| *paths.get(x, energy.height - 1))
    .unwrap();
  for y in (0 .. energy.height - 2).rev() {
    let ancestor = *path.get(0, y + 1) as isize;
    let (x, _path_energy) =
      [ancestor - 1, ancestor, ancestor + 1].iter()
        .filter_map(|&x| {
          if x < 0 || x >= data.width as isize {
            None
          } else {
            Some((x as usize, paths.get(x as usize, y)))
          }
        })
        .min_by_key(|&(_x, path_energy)| path_energy)
        .unwrap();
    *path.get_mut(0, y) = x;
  }

  let mut new_data = vec2d::new(data.width, data.height, pixel::empty());
  for y in 0 .. data.height {
    for x in 0 .. data.width {
      match x.cmp(&path.get(0, y)) {
        std::cmp::Ordering::Equal => {
          let mut data = *data.get(x, y);
          data[0] = 255;
          data[1] = 0;
          data[2] = 0;
          *new_data.get_mut(x, y) = data;
        },
        _ => {
          *new_data.get_mut(x, y) = *data.get(x, y);
        },
      }
    }
  }

  new_data
}
<|endoftext|>


<commit_before>//! The Runner is where all the examples are actually executed.
//!
//! A Runner is instanciated by using [`context::describe`](../context/fn.describe.html) and
//! [`context::rdescribe`](../context/fn.rdescribe.html). You should not try to instanciate
//! a Runner directly.
//!
//! The main methods are `Runner::run` and `Runner::result`.

use context::*;
use events;
use events::Event;
use example_result;
use example_result::ExampleResult;

pub type RunnerResult = Result<TestReport, TestReport>;

/// Handlers is a separate struct which only holds the registered handlers.
/// This is useful to Runner so that its recursive call doesn't have to keep a refernce to `self`
#[derive(Default)]
struct Handlers<'a> {
    handlers: Vec<&'a mut events::EventHandler>,
}

impl<'a> Handlers<'a> {
    fn broadcast(&mut self, event: &events::Event) {
        for h in &mut self.handlers {
            h.trigger(event)
        }
    }
}

pub struct Runner<'a> {
    describe: Context<'a>,
    report: Option<RunnerResult>,
    handlers: Handlers<'a>,
}

impl<'a> Runner<'a> {
    pub fn new(context: Context<'a>) -> Runner<'a> {
        Runner {
            describe: context,
            handlers: Handlers::default(),
            report: None,
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub struct TestReport {
    pub total_tests: u32,
    pub success_count: u32,
    pub error_count: u32,
}

impl<'a> Runner<'a> {

    #[cfg_attr(feature="clippy", allow(redundant_closure))]
    fn run_test(test_name: &str,
                mut test_function: Box<TestFunction>,
                handlers: &mut Handlers)
                -> ExampleResult {

        use std::panic::{catch_unwind, AssertUnwindSafe};
        use example_result;

        handlers.broadcast(&Event::StartTest(String::from(test_name)));
        let res = catch_unwind(AssertUnwindSafe(|| test_function()));

        let res = match res {
            Ok(res) => res,
            // if test panicked, it means that it failed
            Err(_) => example_result::FAILED_RES
        };
        handlers.broadcast(&Event::EndTest(res));
        res
    }

    fn run_and_recurse(report: &mut TestReport,
                       child_ctx: &mut Context,
                       handlers: &mut Handlers)
                       -> ExampleResult {

        use std::mem;
        let mut result = example_result::SUCCESS_RES;

        // As Runner::run consomes the runner, we can deconstruct the context tree as we travel
        // among it.
        // This effectively takes ownership of the context node and replace it with an empty one.
        let ctx = mem::replace(child_ctx, Context::default());

        let tests = ctx.tests;
        let mut before_functions = ctx.before_each;
        let mut after_functions = ctx.after_each;

        for mut test_function in tests {
            let test_res = {
                for before_function in before_functions.iter_mut() {
                    before_function()
                }
                let res = match test_function {
                    Testable::Test(name, test_function) => {
                        Runner::run_test(&name, test_function, handlers)
                    }
                    Testable::Describe(ref name, ref mut desc) => {
                        handlers.broadcast(&Event::StartDescribe(name.clone()));
                        let res = Runner::run_and_recurse(report, desc, handlers);
                        handlers.broadcast(&Event::EndDescribe);
                        res
                    }
                };
                for after_function in after_functions.iter_mut() {
                    after_function()
                }
                res
            };

            report.total_tests += 1;

            if test_res.is_ok() {
                report.success_count += 1;
            } else {
                report.error_count += 1
            }

            result = test_res.or(result);
        }

        result
    }

    pub fn run(mut self) -> RunnerResult {
        self.handlers.broadcast(&Event::StartRunner);

        let mut report = TestReport::default();
        let result = Runner::run_and_recurse(&mut report, &mut self.describe, &mut self.handlers);
        let result = result.res().and(Ok(report)).or_else(|_| Err(report));

        self.handlers.broadcast(&Event::FinishedRunner(result));
        result
    }

    pub fn result(&self) -> RunnerResult {
        self.report.unwrap_or_else(|| Ok(TestReport::default()))
    }

    pub fn add_event_handler<H: events::EventHandler>(&mut self, handler: &'a mut H) {
        self.handlers.handlers.push(handler)
    }
}

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

    mod run {
        pub use super::*;

        #[test]
        fn it_create_a_runner_that_can_be_runned() {
            let runner = describe("A root", |ctx| {
                ctx.it("is expected to run", || {
                    assert_eq!(true, true);
                    Ok(()) as Result<(),()>
                })
            });
            assert!(runner.run().is_ok());
        }

        #[test]
        fn effectively_run_tests() {
            let ran = &mut false;

            {
                let runner = describe("A root", |ctx| {
                    ctx.it("is expected to run", || {
                        *ran = true;
                        Ok(()) as Result<(),()>
                    })
                });
                runner.run().unwrap();
            }

            assert_eq!(true, *ran)
        }

        #[test]
        fn effectively_run_two_tests() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let ran_counter = &mut AtomicUsize::new(0);

            {
                let runner = describe("A root", |ctx| {
                    ctx.it("first run", || {
                        ran_counter.fetch_add(1, Ordering::Relaxed);
                        Ok(()) as Result<(),()>
                    });
                    ctx.it("second run", || {
                        ran_counter.fetch_add(1, Ordering::Relaxed);
                        Ok(()) as Result<(),()>
                    });
                });
                runner.run().unwrap();
            }

            assert_eq!(2, ran_counter.load(Ordering::Relaxed))
        }

        #[test]
        fn effectively_run_two_tests_in_nested_describe() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let ran_counter = &mut AtomicUsize::new(0);

            {
                let runner = describe("A root", |ctx| {
                    ctx.describe("first describe", |ctx| {
                        ctx.it("first run", || {
                            ran_counter.fetch_add(1, Ordering::Relaxed);
                            Ok(()) as Result<(),()>
                        });
                    });
                    ctx.describe("second describe", |ctx| {
                        ctx.it("second run", || {
                            ran_counter.fetch_add(1, Ordering::Relaxed);
                            Ok(()) as Result<(),()>
                        });
                    });
                    ctx.describe("third describe", |ctx| {
                        ctx.describe("fourth describe", |ctx| {
                            ctx.it("third run", || {
                                ran_counter.fetch_add(1, Ordering::Relaxed);
                                Ok(()) as Result<(),()>
                            });
                        })
                    })
                });
                runner.run().unwrap();
            }

            assert_eq!(3, ran_counter.load(Ordering::Relaxed))
        }

        mod events {
            pub use super::*;
            pub use events::*;
            pub use events::Event::*;

            #[derive(Default)]
            struct StubEventHandler {
                pub events: Vec<Event>,
            }

            impl EventHandler for StubEventHandler {
                fn trigger(&mut self, event: &Event) {
                    self.events.push(event.clone())
                }
            }

            #[test]
            fn start_runner_event_is_sent() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartRunner), handler.events.get(0))
            }

            #[test]
            fn no_event_when_no_run() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);
                }

                assert_eq!(None, handler.events.get(0))
            }

            #[test]
            fn finished_runner_event_is_last_event_sent() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                if let Some(&FinishedRunner(_)) = handler.events.last() {
                    assert!(true);
                } else {
                    assert!(false, "FinishedRunner event not sent at last")
                }
            }

            #[test]
            fn finished_runner_event_has_correct_test_report() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("one good test",
                                              |ctx| ctx.it("is a good test", || Ok(()) as Result<(),()>));
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                if let Some(&FinishedRunner(Ok(report))) = handler.events.last() {
                    let expected_report = TestReport {
                        total_tests: 1,
                        success_count: 1,
                        error_count: 0,
                    };
                    assert_eq!(expected_report, report)
                } else {
                    assert!(false, "FinishedRunner send bad TestReport")
                }
            }

            #[test]
            fn start_test_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root", |ctx| {
                        ctx.it("should run with an event", || Ok(()) as Result<(),()>);
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartTest(String::from("should run with an event"))),
                           handler.events.get(1))
            }

            #[test]
            fn end_test_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root", |ctx| {
                        ctx.it("should run with an event", || Ok(()) as Result<(),()>);
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&EndTest(SUCCESS_RES)), handler.events.get(2));
            }

            #[test]
            fn start_describe_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root, no hook", |ctx| {
                        ctx.describe("this has a hook", |_| {});
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartDescribe(String::from("this has a hook"))),
                           handler.events.get(1));
            }

            #[test]
            fn end_describe_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root, no hook", |ctx| {
                        ctx.describe("this has a hook", |_| {});
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&EndDescribe), handler.events.get(2));
            }
        }
    }

    mod results {
        pub use super::*;

        #[test]
        fn tests_can_fail_with_an_error_result() {
            let runner = describe("A root", |ctx| ctx.it("should fail", || Err(()) as Result<(),()>));
            let result = runner.run();

            assert!(result.is_err());
        }

        #[test]
        fn should_be_ok_if_tests_are_ok() {
            let runner = describe("A root", |ctx| ctx.it("should be ok", || Ok(()) as Result<(),()>));
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn is_ok_if_no_tests_have_been_runned() {
            let runner = describe("A root", |_ctx| {});
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn is_err_if_one_test_is_err() {
            let runner = describe("A root", |ctx| {
                ctx.it("an err", || Err(()) as Result<(),()>);
                ctx.it("an ok", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_err());
        }

        #[test]
        fn is_ok_if_all_tests_are_ok() {
            let runner = describe("A root", |ctx| {
                ctx.it("ok 1", || Ok(()) as Result<(),()>);
                ctx.it("ok 2", || Ok(()) as Result<(),()>);
                ctx.it("ok 3", || Ok(()) as Result<(),()>);
                ctx.it("ok 4", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn correctly_count_errors() {
            let runner = describe("a root", |ctx| {
                ctx.it("first is ok", || ());
                ctx.it("second is not", || false);
            });

            if let Err(res) = runner.run() {
                assert_eq!((1, 1),
                           (res.success_count, res.error_count));
            } else {
                assert!(false, "unreachable");
            }

        }

        #[test]
        fn tests_can_contains_asserts_that_panic() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let counter = &mut AtomicUsize::new(0);

            let runner = describe("A root", |ctx| {
                ctx.it("assert_eq fail", || {
                    assert_eq!(true, false);
                    Ok(()) as Result<(),()>
                });
                ctx.it("this should also be runned", || {
                    counter.fetch_add(1, Ordering::Relaxed);
                    Ok(()) as Result<(),()>
                })
            });
            let result = runner.run();

            // TODO refactor this to tuple
            assert!(result.is_err());
            assert_eq!(1, counter.load(Ordering::Relaxed));
        }

        #[test]
        fn can_count_the_tests() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Ok(()) as Result<(),()>);
                ctx.it("second", || Ok(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let results = runner.run();

            assert!(results.is_ok());
            if let Ok(report) = results {
                assert_eq!(3, report.total_tests);
            }
        }

        #[test]
        fn can_count_succes() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Ok(()) as Result<(),()>);
                ctx.it("second", || Ok(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_ok());
            if let Ok(report) = result {
                assert_eq!(3, report.success_count);
            }
        }

        #[test]
        fn can_count_errors() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Err(()) as Result<(),()>);
                ctx.it("second", || Err(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_err());
            if let Err(report) = result {
                assert_eq!(2, report.error_count);
            }
        }
    }
}
<commit_msg> refactor runner: simplify run_test<commit_after>//! The Runner is where all the examples are actually executed.
//!
//! A Runner is instanciated by using [`context::describe`](../context/fn.describe.html) and
//! [`context::rdescribe`](../context/fn.rdescribe.html). You should not try to instanciate
//! a Runner directly.
//!
//! The main methods are `Runner::run` and `Runner::result`.

use context::*;
use events;
use events::Event;
use example_result;
use example_result::ExampleResult;

pub type RunnerResult = Result<TestReport, TestReport>;

/// Handlers is a separate struct which only holds the registered handlers.
/// This is useful to Runner so that its recursive call doesn't have to keep a refernce to `self`
#[derive(Default)]
struct Handlers<'a> {
    handlers: Vec<&'a mut events::EventHandler>,
}

impl<'a> Handlers<'a> {
    fn broadcast(&mut self, event: &events::Event) {
        for h in &mut self.handlers {
            h.trigger(event)
        }
    }
}

pub struct Runner<'a> {
    describe: Context<'a>,
    report: Option<RunnerResult>,
    handlers: Handlers<'a>,
}

impl<'a> Runner<'a> {
    pub fn new(context: Context<'a>) -> Runner<'a> {
        Runner {
            describe: context,
            handlers: Handlers::default(),
            report: None,
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub struct TestReport {
    pub total_tests: u32,
    pub success_count: u32,
    pub error_count: u32,
}

impl<'a> Runner<'a> {

    #[cfg_attr(feature="clippy", allow(redundant_closure))]
    fn run_test(mut test_function: Box<TestFunction>)
                -> ExampleResult {

        use std::panic::{catch_unwind, AssertUnwindSafe};
        use example_result;

        let res = catch_unwind(AssertUnwindSafe(|| test_function()));

        res.unwrap_or_else(|_| example_result::FAILED_RES)
    }

    fn run_and_recurse(report: &mut TestReport,
                       child_ctx: &mut Context,
                       handlers: &mut Handlers)
                       -> ExampleResult {

        use std::mem;
        let mut result = example_result::SUCCESS_RES;

        // As Runner::run consomes the runner, we can deconstruct the context tree as we travel
        // among it.
        // This effectively takes ownership of the context node and replace it with an empty one.
        let ctx = mem::replace(child_ctx, Context::default());

        let tests = ctx.tests;
        let mut before_functions = ctx.before_each;
        let mut after_functions = ctx.after_each;

        for mut test_function in tests {
            let test_res = {
                for before_function in before_functions.iter_mut() {
                    before_function()
                }
                let res = match test_function {
                    Testable::Test(name, test_function) => {
                        handlers.broadcast(&Event::StartTest(name));
                        let res = Runner::run_test(test_function);
                        handlers.broadcast(&Event::EndTest(res));
                        res
                    }
                    Testable::Describe(ref name, ref mut desc) => {
                        handlers.broadcast(&Event::StartDescribe(name.clone()));
                        let res = Runner::run_and_recurse(report, desc, handlers);
                        handlers.broadcast(&Event::EndDescribe);
                        res
                    }
                };
                for after_function in after_functions.iter_mut() {
                    after_function()
                }
                res
            };

            report.total_tests += 1;

            if test_res.is_ok() {
                report.success_count += 1;
            } else {
                report.error_count += 1
            }

            result = test_res.or(result);
        }

        result
    }

    pub fn run(mut self) -> RunnerResult {
        self.handlers.broadcast(&Event::StartRunner);

        let mut report = TestReport::default();
        let result = Runner::run_and_recurse(&mut report, &mut self.describe, &mut self.handlers);
        let result = result.res().and(Ok(report)).or_else(|_| Err(report));

        self.handlers.broadcast(&Event::FinishedRunner(result));
        result
    }

    pub fn result(&self) -> RunnerResult {
        self.report.unwrap_or_else(|| Ok(TestReport::default()))
    }

    pub fn add_event_handler<H: events::EventHandler>(&mut self, handler: &'a mut H) {
        self.handlers.handlers.push(handler)
    }
}

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

    mod run {
        pub use super::*;

        #[test]
        fn it_create_a_runner_that_can_be_runned() {
            let runner = describe("A root", |ctx| {
                ctx.it("is expected to run", || {
                    assert_eq!(true, true);
                    Ok(()) as Result<(),()>
                })
            });
            assert!(runner.run().is_ok());
        }

        #[test]
        fn effectively_run_tests() {
            let ran = &mut false;

            {
                let runner = describe("A root", |ctx| {
                    ctx.it("is expected to run", || {
                        *ran = true;
                        Ok(()) as Result<(),()>
                    })
                });
                runner.run().unwrap();
            }

            assert_eq!(true, *ran)
        }

        #[test]
        fn effectively_run_two_tests() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let ran_counter = &mut AtomicUsize::new(0);

            {
                let runner = describe("A root", |ctx| {
                    ctx.it("first run", || {
                        ran_counter.fetch_add(1, Ordering::Relaxed);
                        Ok(()) as Result<(),()>
                    });
                    ctx.it("second run", || {
                        ran_counter.fetch_add(1, Ordering::Relaxed);
                        Ok(()) as Result<(),()>
                    });
                });
                runner.run().unwrap();
            }

            assert_eq!(2, ran_counter.load(Ordering::Relaxed))
        }

        #[test]
        fn effectively_run_two_tests_in_nested_describe() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let ran_counter = &mut AtomicUsize::new(0);

            {
                let runner = describe("A root", |ctx| {
                    ctx.describe("first describe", |ctx| {
                        ctx.it("first run", || {
                            ran_counter.fetch_add(1, Ordering::Relaxed);
                            Ok(()) as Result<(),()>
                        });
                    });
                    ctx.describe("second describe", |ctx| {
                        ctx.it("second run", || {
                            ran_counter.fetch_add(1, Ordering::Relaxed);
                            Ok(()) as Result<(),()>
                        });
                    });
                    ctx.describe("third describe", |ctx| {
                        ctx.describe("fourth describe", |ctx| {
                            ctx.it("third run", || {
                                ran_counter.fetch_add(1, Ordering::Relaxed);
                                Ok(()) as Result<(),()>
                            });
                        })
                    })
                });
                runner.run().unwrap();
            }

            assert_eq!(3, ran_counter.load(Ordering::Relaxed))
        }

        mod events {
            pub use super::*;
            pub use events::*;
            pub use events::Event::*;

            #[derive(Default)]
            struct StubEventHandler {
                pub events: Vec<Event>,
            }

            impl EventHandler for StubEventHandler {
                fn trigger(&mut self, event: &Event) {
                    self.events.push(event.clone())
                }
            }

            #[test]
            fn start_runner_event_is_sent() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartRunner), handler.events.get(0))
            }

            #[test]
            fn no_event_when_no_run() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);
                }

                assert_eq!(None, handler.events.get(0))
            }

            #[test]
            fn finished_runner_event_is_last_event_sent() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                if let Some(&FinishedRunner(_)) = handler.events.last() {
                    assert!(true);
                } else {
                    assert!(false, "FinishedRunner event not sent at last")
                }
            }

            #[test]
            fn finished_runner_event_has_correct_test_report() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("one good test",
                                              |ctx| ctx.it("is a good test", || Ok(()) as Result<(),()>));
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                if let Some(&FinishedRunner(Ok(report))) = handler.events.last() {
                    let expected_report = TestReport {
                        total_tests: 1,
                        success_count: 1,
                        error_count: 0,
                    };
                    assert_eq!(expected_report, report)
                } else {
                    assert!(false, "FinishedRunner send bad TestReport")
                }
            }

            #[test]
            fn start_test_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root", |ctx| {
                        ctx.it("should run with an event", || Ok(()) as Result<(),()>);
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartTest(String::from("should run with an event"))),
                           handler.events.get(1))
            }

            #[test]
            fn end_test_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root", |ctx| {
                        ctx.it("should run with an event", || Ok(()) as Result<(),()>);
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&EndTest(SUCCESS_RES)), handler.events.get(2));
            }

            #[test]
            fn start_describe_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root, no hook", |ctx| {
                        ctx.describe("this has a hook", |_| {});
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartDescribe(String::from("this has a hook"))),
                           handler.events.get(1));
            }

            #[test]
            fn end_describe_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root, no hook", |ctx| {
                        ctx.describe("this has a hook", |_| {});
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&EndDescribe), handler.events.get(2));
            }
        }
    }

    mod results {
        pub use super::*;

        #[test]
        fn tests_can_fail_with_an_error_result() {
            let runner = describe("A root", |ctx| ctx.it("should fail", || Err(()) as Result<(),()>));
            let result = runner.run();

            assert!(result.is_err());
        }

        #[test]
        fn should_be_ok_if_tests_are_ok() {
            let runner = describe("A root", |ctx| ctx.it("should be ok", || Ok(()) as Result<(),()>));
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn is_ok_if_no_tests_have_been_runned() {
            let runner = describe("A root", |_ctx| {});
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn is_err_if_one_test_is_err() {
            let runner = describe("A root", |ctx| {
                ctx.it("an err", || Err(()) as Result<(),()>);
                ctx.it("an ok", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_err());
        }

        #[test]
        fn is_ok_if_all_tests_are_ok() {
            let runner = describe("A root", |ctx| {
                ctx.it("ok 1", || Ok(()) as Result<(),()>);
                ctx.it("ok 2", || Ok(()) as Result<(),()>);
                ctx.it("ok 3", || Ok(()) as Result<(),()>);
                ctx.it("ok 4", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn correctly_count_errors() {
            let runner = describe("a root", |ctx| {
                ctx.it("first is ok", || ());
                ctx.it("second is not", || false);
            });

            if let Err(res) = runner.run() {
                assert_eq!((1, 1),
                           (res.success_count, res.error_count));
            } else {
                assert!(false, "unreachable");
            }

        }

        #[test]
        fn tests_can_contains_asserts_that_panic() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let counter = &mut AtomicUsize::new(0);

            let runner = describe("A root", |ctx| {
                ctx.it("assert_eq fail", || {
                    assert_eq!(true, false);
                    Ok(()) as Result<(),()>
                });
                ctx.it("this should also be runned", || {
                    counter.fetch_add(1, Ordering::Relaxed);
                    Ok(()) as Result<(),()>
                })
            });
            let result = runner.run();

            // TODO refactor this to tuple
            assert!(result.is_err());
            assert_eq!(1, counter.load(Ordering::Relaxed));
        }

        #[test]
        fn can_count_the_tests() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Ok(()) as Result<(),()>);
                ctx.it("second", || Ok(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let results = runner.run();

            assert!(results.is_ok());
            if let Ok(report) = results {
                assert_eq!(3, report.total_tests);
            }
        }

        #[test]
        fn can_count_succes() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Ok(()) as Result<(),()>);
                ctx.it("second", || Ok(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_ok());
            if let Ok(report) = result {
                assert_eq!(3, report.success_count);
            }
        }

        #[test]
        fn can_count_errors() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Err(()) as Result<(),()>);
                ctx.it("second", || Err(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_err());
            if let Err(report) = result {
                assert_eq!(2, report.error_count);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;

use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use convert::{ IntoSV, FromRaw };

pub struct SV(Owned<raw::SV>);

impl SV {
    pub fn iv(&self) -> IV {
        let r = &*self.0;
        unsafe { r.pthx().sv_iv(r.as_ptr()) }
    }

    pub fn uv(&self) -> UV {
        let r = &*self.0;
        unsafe { r.pthx().sv_uv(r.as_ptr()) }
    }

    pub fn nv(&self) -> NV {
        let r = &*self.0;
        unsafe { r.pthx().sv_nv(r.as_ptr()) }
    }

    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }
}

impl FromRaw<raw::SV> for IV {
    unsafe fn from_raw(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromRaw<raw::SV> for SV {
    unsafe fn from_raw(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl IntoSV for IV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw(pthx, pthx.new_sv_nv(self)) }
    }
}

impl<'a> IntoSV for &'a str {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        use std::ffi::CString;
        let buf = CString::new(self).unwrap();
        unsafe {
            let svp = pthx.new_sv_pvn(buf.as_ptr(), self.len() as raw::STRLEN, raw::SVf_UTF8 as raw::U32);
            SV::from_raw(pthx, svp)
        }
    }
}
<commit_msg>Fix leak.<commit_after>use std::mem;

use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use convert::{ IntoSV, FromRaw };

pub struct SV(Owned<raw::SV>);

impl SV {
    pub fn iv(&self) -> IV {
        let r = &*self.0;
        unsafe { r.pthx().sv_iv(r.as_ptr()) }
    }

    pub fn uv(&self) -> UV {
        let r = &*self.0;
        unsafe { r.pthx().sv_uv(r.as_ptr()) }
    }

    pub fn nv(&self) -> NV {
        let r = &*self.0;
        unsafe { r.pthx().sv_nv(r.as_ptr()) }
    }

    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }
}

impl FromRaw<raw::SV> for IV {
    unsafe fn from_raw(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromRaw<raw::SV> for SV {
    unsafe fn from_raw(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl IntoSV for IV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl<'a> IntoSV for &'a str {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        use std::ffi::CString;
        let buf = CString::new(self).unwrap();
        unsafe {
            let svp = pthx.new_sv_pvn(buf.as_ptr(), self.len() as raw::STRLEN, raw::SVf_UTF8 as raw::U32);
            SV::from_raw(pthx, svp)
        }
    }
}
<|endoftext|>