<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(plugin)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_name = "fourcc"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]

#![feature(plugin_registrar)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use rustc::plugin::Registry;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("fourcc", expand_syntax_ext);
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult + 'static> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitInt(val as u64, ast::UnsignedIntLit(ast::TyU32)));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt,
             tts: &[ast::TokenTree]) -> (P<ast::Expr>, Option<Ident>) {
    let p = &mut cx.new_parser_from_tts(tts);
    let ex = p.parse_expr();
    let id = if p.token == token::Eof {
        None
    } else {
        p.expect(&token::Comma);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::Eof {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), &*meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<commit_msg>update comment style to conventions<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Syntax extension to generate FourCCs.
//!
//! Once loaded, fourcc!() is called with a single 4-character string,
//! and an optional ident that is either `big`, `little`, or `target`.
//! The ident represents endianness, and specifies in which direction
//! the characters should be read. If the ident is omitted, it is assumed
//! to be `big`, i.e. left-to-right order. It returns a u32.
//!
//! # Examples
//!
//! To load the extension and use it:
//!
//! ```rust,ignore
//! #[phase(plugin)]
//! extern crate fourcc;
//!
//! fn main() {
//!     let val = fourcc!("\xC0\xFF\xEE!");
//!     assert_eq!(val, 0xC0FFEE21u32);
//!     let little_val = fourcc!("foo ", little);
//!     assert_eq!(little_val, 0x21EEFFC0u32);
//! }
//! ```
//!
//! # References
//!
//! * [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

#![crate_name = "fourcc"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]

#![feature(plugin_registrar)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use rustc::plugin::Registry;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("fourcc", expand_syntax_ext);
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult + 'static> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitInt(val as u64, ast::UnsignedIntLit(ast::TyU32)));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt,
             tts: &[ast::TokenTree]) -> (P<ast::Expr>, Option<Ident>) {
    let p = &mut cx.new_parser_from_tts(tts);
    let ex = p.parse_expr();
    let id = if p.token == token::Eof {
        None
    } else {
        p.expect(&token::Comma);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::Eof {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), &*meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<|endoftext|>


<commit_before>//! kaiseki -- literate programming preprocessing

#[macro_use] extern crate error_chain;
extern crate regex;

pub mod input;
pub mod list;

mod parsing;

pub mod processing_errors {
  error_chain! {
    errors {
      NotUTF8(file: String, lineno: usize) {
        description("line is not valid UTF-8")
        display("error: '{}', line {}: not valid UTF-8", file, lineno)
      }

      MalformedAnchor(file: String, lineno: usize, anchor: String) {
        description("could not parse anchor tag")
        display("warn: '{}', line {}: ignoring malformed anchor: '{}'", file, lineno, anchor)
      }

      DuplicateAnchor(file: String, lineno: usize, tag: String) {
        description("found a duplicate anchor tag")
        display("warn: '{}', line {}: ignoring duplicate anchor tag: '{}'", file, lineno, tag)
      }

      MissingTag(file: String, lineno: usize, tag: String) {
        description("nonexistent tag name")
        display("warn: '{}', line {}: nonexistent tag name: '{}'", file, lineno, tag)
      }
    }
  }
}

use std::rc::Rc;
use std::io;
use std::result;

use std::collections::BTreeMap;

use input::File;
use list::List;

pub struct OutputOptions {
  pub comment: Option<String>
}

struct Block {
  lines: Vec<String>,
  file: Rc<String>,
  lineno: usize
}

impl Block {
  fn new(file: Rc<String>, lineno: usize) -> Self {
    Block {
      lines: Vec::new(),
      file: file,
      lineno: lineno
    }
  }
}

struct Anchor {
  indentation: usize,  // The *absolute* level of indentation.
  tangled: Tangled
}

impl Anchor {
  fn new(indentation: usize) -> Self {
    Anchor {
      indentation: indentation,
      tangled: List::new()
    }
  }
}

/// Essentially a Result. But it makes the types more intuitive to read.
enum Either<T, U> {
  Left(T),
  Right(U)
}

struct AnchorRef(String);

type Tangled = List<Either<Block, AnchorRef>>;

enum OutputTarget {
  Insert,
  Before(AnchorRef),
  After(AnchorRef)
}

/// Process all the literate programming directives in the contents of the
/// given files, return a Vec of output lines (suitable for immediate
/// printing to, say, `stdout`)
pub fn tangle_output(inputs: Vec<File>, options: OutputOptions) -> (Vec<String>, Vec<processing_errors::Error>) {
  use std::io::{BufReader, BufRead};

  use parsing::Anchor;
  use processing_errors::ErrorKind;

  let mut tangled = List::new();
  let mut anchors = BTreeMap::new();
  let mut errors = Vec::new();  // Errors that we accrue during processing.

  for input in inputs {
    let filename = Rc::new(input.name);

    let mut lines = BufReader::new(input.contents)
      .lines()
      .enumerate()
      .map(|(lineno, line)| (lineno + 1, line));
    let mut state = OutputTarget::Insert;
    let mut tangled_section = List::new();
    let mut block = Block::new(filename.clone(), 1);

    macro_rules! emplace_section {
      () => {
        match state {
          OutputTarget::Insert => tangled.append_back(&mut tangled_section),
          OutputTarget::Before(AnchorRef(anchor_name)) => {
            let anchor: &mut ::Anchor = anchors.get_mut(&anchor_name)
              .expect("invariant violated: anchor name does not exist");
            anchor.tangled.append_front(&mut tangled_section);
          },
          OutputTarget::After(AnchorRef(anchor_name)) => {
            let anchor: &mut ::Anchor = anchors.get_mut(&anchor_name)
              .expect("invariant violated: anchor name does not exist");
            anchor.tangled.append_back(&mut tangled_section);
          }
        }
      }
    }

    loop {
      let next_anchor = process_block_lines(&mut lines, &mut block, &mut errors);

      if !block.lines.is_empty() {
        tangled_section.push_back(Either::Left(block));
      }

      match next_anchor {
        Some((lineno, indentation, anchor)) => {
          macro_rules! has_anchor {
            ($anchor_name:expr) => {{
              if anchors.contains_key($anchor_name) {
                true
              } else {
                let filename: &String = &filename;
                let error = ErrorKind::MissingTag(filename.clone(), lineno, $anchor_name.clone()).into();
                errors.push(error);
                false
              }
            }}
          }

          block = Block::new(filename.clone(), lineno);
          match anchor {
            Anchor::Insert => {
              emplace_section!();
              tangled_section = List::new();
              state = OutputTarget::Insert;
            },
            Anchor::Before(anchor_name) => {
              emplace_section!();
              tangled_section = List::new();
              if has_anchor!(&anchor_name) {
                state = OutputTarget::Before(AnchorRef(anchor_name));
              } else {
                state = OutputTarget::Insert;
              }
            },
            Anchor::After(anchor_name) => {
              emplace_section!();
              tangled_section = List::new();
              if has_anchor!(&anchor_name) {
                state = OutputTarget::After(AnchorRef(anchor_name));
              } else {
                state = OutputTarget::Insert;
              }
            },
            Anchor::Label(anchor_name) => {
              let anchor = ::Anchor::new(indentation);
              anchors.insert(anchor_name.clone(), anchor);
              tangled_section.push_back(Either::Right(AnchorRef(anchor_name)));
            }
          };
        },
        None => {
          emplace_section!();
          break;
        }
      };
    }
  }

  (collect_tangled_output(tangled, anchors, options), errors)
}

fn collect_tangled_output(tangled: Tangled,
                          mut anchors: BTreeMap<String, Anchor>,
                          options: OutputOptions) -> Vec<String>
{
  let mut lines = Vec::new();
  collect_anchor_lines(tangled, &mut anchors, &mut lines, 0, &options);
  lines
}

fn maybe_block_header(block: &Block, options: &OutputOptions) -> Option<String> {
  match &options.comment {
    &Some(ref comment_prefix) => {
      let header = format!(
        "{} '{}', line {}",
        comment_prefix,
        &block.file,
        block.lineno
      );

      Some(header)
    }
    &None => None
  }
}

fn collect_anchor_lines(tangled: Tangled,
                        anchors: &mut BTreeMap<String, Anchor>,
                        lines: &mut Vec<String>,
                        indentation: usize,
                        options: &OutputOptions)
{
  use std::iter;

  let indent_prefix = iter::repeat(' ').take(indentation).collect::<String>();

  for knot in tangled {
    match knot {
      Either::Left(block) => {
        if let Some(comment) = maybe_block_header(&block, options) {
          lines.push(indent_prefix.clone() + &comment);
        }

        for line in block.lines {
          lines.push(indent_prefix.clone() + &line);
        }
      },
      Either::Right(AnchorRef(ref anchor_name)) => {
        let anchor = anchors.remove(anchor_name)
          .expect("invariant violated: anchor name does not exist");

        collect_anchor_lines(
          anchor.tangled,
          anchors,
          lines,
          indentation + anchor.indentation,
          options
        );
      }
    };
  }
}

/// We scan through each file block by block.
/// Each block will end in either an anchor tag, or the end of the file.
fn process_block_lines<I>(lines: &mut I, block: &mut Block, errors: &mut Vec<processing_errors::Error>) -> Option<(usize, usize, parsing::Anchor)> where
  I: Iterator<Item=(usize, result::Result<String, io::Error>)>
{
  use processing_errors::ErrorKind;
  use std::ops::Deref;

  let filename = block.file.deref();

  for (lineno, line) in lines {
    match line {
      Ok(line) => {
        let result = parsing::might_be_anchor(&line)
          .ok_or(None)
          .and_then(|found| {
            parsing::parse(found.as_str())
              .map_err(|_| Some(ErrorKind::MalformedAnchor(
                filename.clone(),
                lineno,
                found.as_str().to_string()
              ).into()))
          });

        match result {
          Ok(anchor) => return Some((lineno, indentation_level(&line), anchor)),
          Err(Some(error)) => {
            errors.push(error);
            block.lines.push(line);
          },
          Err(None) => {
            block.lines.push(line);
          }
        };
      },
      Err(_) => errors.push(ErrorKind::NotUTF8(filename.clone(), lineno).into())
    };
  }

  None
}

/// Index of first non-whitespace character.
fn indentation_level(line: &str) -> usize {
  use regex::Regex;

  let nonwhitespace = Regex::new(r"[^\s]").unwrap();
  match nonwhitespace.find(line) {
    Some(found) => found.start(),
    None => 0
  }
}
<commit_msg>add default value for outputoptions<commit_after>//! kaiseki -- literate programming preprocessing

#[macro_use] extern crate error_chain;
extern crate regex;

pub mod input;
pub mod list;

mod parsing;

pub mod processing_errors {
  error_chain! {
    errors {
      NotUTF8(file: String, lineno: usize) {
        description("line is not valid UTF-8")
        display("error: '{}', line {}: not valid UTF-8", file, lineno)
      }

      MalformedAnchor(file: String, lineno: usize, anchor: String) {
        description("could not parse anchor tag")
        display("warn: '{}', line {}: ignoring malformed anchor: '{}'", file, lineno, anchor)
      }

      DuplicateAnchor(file: String, lineno: usize, tag: String) {
        description("found a duplicate anchor tag")
        display("warn: '{}', line {}: ignoring duplicate anchor tag: '{}'", file, lineno, tag)
      }

      MissingTag(file: String, lineno: usize, tag: String) {
        description("nonexistent tag name")
        display("warn: '{}', line {}: nonexistent tag name: '{}'", file, lineno, tag)
      }
    }
  }
}

use std::rc::Rc;
use std::io;
use std::result;
use std::default::Default;

use std::collections::BTreeMap;

use input::File;
use list::List;

pub struct OutputOptions {
  pub comment: Option<String>
}

impl Default for OutputOptions {
  fn default() -> Self {
    OutputOptions {
      comment: None
    }
  }
}

struct Block {
  lines: Vec<String>,
  file: Rc<String>,
  lineno: usize
}

impl Block {
  fn new(file: Rc<String>, lineno: usize) -> Self {
    Block {
      lines: Vec::new(),
      file: file,
      lineno: lineno
    }
  }
}

struct Anchor {
  indentation: usize,  // The *absolute* level of indentation.
  tangled: Tangled
}

impl Anchor {
  fn new(indentation: usize) -> Self {
    Anchor {
      indentation: indentation,
      tangled: List::new()
    }
  }
}

/// Essentially a Result. But it makes the types more intuitive to read.
enum Either<T, U> {
  Left(T),
  Right(U)
}

struct AnchorRef(String);

type Tangled = List<Either<Block, AnchorRef>>;

enum OutputTarget {
  Insert,
  Before(AnchorRef),
  After(AnchorRef)
}

/// Process all the literate programming directives in the contents of the
/// given files, return a Vec of output lines (suitable for immediate
/// printing to, say, `stdout`)
pub fn tangle_output(inputs: Vec<File>, options: OutputOptions) -> (Vec<String>, Vec<processing_errors::Error>) {
  use std::io::{BufReader, BufRead};

  use parsing::Anchor;
  use processing_errors::ErrorKind;

  let mut tangled = List::new();
  let mut anchors = BTreeMap::new();
  let mut errors = Vec::new();  // Errors that we accrue during processing.

  for input in inputs {
    let filename = Rc::new(input.name);

    let mut lines = BufReader::new(input.contents)
      .lines()
      .enumerate()
      .map(|(lineno, line)| (lineno + 1, line));
    let mut state = OutputTarget::Insert;
    let mut tangled_section = List::new();
    let mut block = Block::new(filename.clone(), 1);

    macro_rules! emplace_section {
      () => {
        match state {
          OutputTarget::Insert => tangled.append_back(&mut tangled_section),
          OutputTarget::Before(AnchorRef(anchor_name)) => {
            let anchor: &mut ::Anchor = anchors.get_mut(&anchor_name)
              .expect("invariant violated: anchor name does not exist");
            anchor.tangled.append_front(&mut tangled_section);
          },
          OutputTarget::After(AnchorRef(anchor_name)) => {
            let anchor: &mut ::Anchor = anchors.get_mut(&anchor_name)
              .expect("invariant violated: anchor name does not exist");
            anchor.tangled.append_back(&mut tangled_section);
          }
        }
      }
    }

    loop {
      let next_anchor = process_block_lines(&mut lines, &mut block, &mut errors);

      if !block.lines.is_empty() {
        tangled_section.push_back(Either::Left(block));
      }

      match next_anchor {
        Some((lineno, indentation, anchor)) => {
          macro_rules! has_anchor {
            ($anchor_name:expr) => {{
              if anchors.contains_key($anchor_name) {
                true
              } else {
                let filename: &String = &filename;
                let error = ErrorKind::MissingTag(filename.clone(), lineno, $anchor_name.clone()).into();
                errors.push(error);
                false
              }
            }}
          }

          block = Block::new(filename.clone(), lineno);
          match anchor {
            Anchor::Insert => {
              emplace_section!();
              tangled_section = List::new();
              state = OutputTarget::Insert;
            },
            Anchor::Before(anchor_name) => {
              emplace_section!();
              tangled_section = List::new();
              if has_anchor!(&anchor_name) {
                state = OutputTarget::Before(AnchorRef(anchor_name));
              } else {
                state = OutputTarget::Insert;
              }
            },
            Anchor::After(anchor_name) => {
              emplace_section!();
              tangled_section = List::new();
              if has_anchor!(&anchor_name) {
                state = OutputTarget::After(AnchorRef(anchor_name));
              } else {
                state = OutputTarget::Insert;
              }
            },
            Anchor::Label(anchor_name) => {
              let anchor = ::Anchor::new(indentation);
              anchors.insert(anchor_name.clone(), anchor);
              tangled_section.push_back(Either::Right(AnchorRef(anchor_name)));
            }
          };
        },
        None => {
          emplace_section!();
          break;
        }
      };
    }
  }

  (collect_tangled_output(tangled, anchors, options), errors)
}

fn collect_tangled_output(tangled: Tangled,
                          mut anchors: BTreeMap<String, Anchor>,
                          options: OutputOptions) -> Vec<String>
{
  let mut lines = Vec::new();
  collect_anchor_lines(tangled, &mut anchors, &mut lines, 0, &options);
  lines
}

fn maybe_block_header(block: &Block, options: &OutputOptions) -> Option<String> {
  match &options.comment {
    &Some(ref comment_prefix) => {
      let header = format!(
        "{} '{}', line {}",
        comment_prefix,
        &block.file,
        block.lineno
      );

      Some(header)
    }
    &None => None
  }
}

fn collect_anchor_lines(tangled: Tangled,
                        anchors: &mut BTreeMap<String, Anchor>,
                        lines: &mut Vec<String>,
                        indentation: usize,
                        options: &OutputOptions)
{
  use std::iter;

  let indent_prefix = iter::repeat(' ').take(indentation).collect::<String>();

  for knot in tangled {
    match knot {
      Either::Left(block) => {
        if let Some(comment) = maybe_block_header(&block, options) {
          lines.push(indent_prefix.clone() + &comment);
        }

        for line in block.lines {
          lines.push(indent_prefix.clone() + &line);
        }
      },
      Either::Right(AnchorRef(ref anchor_name)) => {
        let anchor = anchors.remove(anchor_name)
          .expect("invariant violated: anchor name does not exist");

        collect_anchor_lines(
          anchor.tangled,
          anchors,
          lines,
          indentation + anchor.indentation,
          options
        );
      }
    };
  }
}

/// We scan through each file block by block.
/// Each block will end in either an anchor tag, or the end of the file.
fn process_block_lines<I>(lines: &mut I, block: &mut Block, errors: &mut Vec<processing_errors::Error>) -> Option<(usize, usize, parsing::Anchor)> where
  I: Iterator<Item=(usize, result::Result<String, io::Error>)>
{
  use processing_errors::ErrorKind;
  use std::ops::Deref;

  let filename = block.file.deref();

  for (lineno, line) in lines {
    match line {
      Ok(line) => {
        let result = parsing::might_be_anchor(&line)
          .ok_or(None)
          .and_then(|found| {
            parsing::parse(found.as_str())
              .map_err(|_| Some(ErrorKind::MalformedAnchor(
                filename.clone(),
                lineno,
                found.as_str().to_string()
              ).into()))
          });

        match result {
          Ok(anchor) => return Some((lineno, indentation_level(&line), anchor)),
          Err(Some(error)) => {
            errors.push(error);
            block.lines.push(line);
          },
          Err(None) => {
            block.lines.push(line);
          }
        };
      },
      Err(_) => errors.push(ErrorKind::NotUTF8(filename.clone(), lineno).into())
    };
  }

  None
}

/// Index of first non-whitespace character.
fn indentation_level(line: &str) -> usize {
  use regex::Regex;

  let nonwhitespace = Regex::new(r"[^\s]").unwrap();
  match nonwhitespace.find(line) {
    Some(found) => found.start(),
    None => 0
  }
}
<|endoftext|>


<commit_before>#[cfg(test)]
use std::collections::BTreeSet;

/// An non-standard iterator yielding combinations of elements from a sequence.
pub struct Combinator<'a, T>
    where T: 'a
{
    seq: &'a [T],
    indices: Vec<usize>,
    inited: bool,
}

impl<'a, 'b, T> Combinator<'a, T> {
    pub fn next(&'b mut self) -> Option<CombinationIter<'a, 'b, T>> {
        let seq_len = self.seq.len();
        let ref mut indices = self.indices;
        let k = indices.len();

        // First permutation is special cased
        if !self.inited {
            self.inited = true;

            return Some(CombinationIter {
                it: indices.iter(),
                seq: self.seq,
            });
        }

        for i in (0..k).rev() {
            // Try and increment this index
            indices[i] += 1;

            if indices[i] == seq_len - k + 1 + i {
                // Index has overflowed, try parent index
                continue;
            }

            // Reset child indices
            for j in i + 1..k {
                indices[j] = indices[j - 1] + 1;
            }

            return Some(CombinationIter {
                it: indices.iter(),
                seq: self.seq,
            });
        }

        return None;
    }
}

/// An `Iterator` yielding references to elements of a particular combination.
pub struct CombinationIter<'a, 'b, T>
    where T: 'a
{
    it: std::slice::Iter<'b, usize>,
    seq: &'a [T],
}

impl<'a, 'b, T> Iterator for CombinationIter<'a, 'b, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(i) = self.it.next() {
            Some(&self.seq[*i])
        } else {
            None
        }
    }
}

/// Returns a (non-standard) iterator yielding all combinations of length `len` from
/// the sequence `seq`.
///
/// Each combination is itself a (standard) `Iterator` yielding references to each element of the
/// combination.
///
/// # Panics
/// When attempting to iterate over combination lengths longer than the original sequence.
///
/// # Examples
///
/// ```
/// use combo::combinations;
///
/// let sequence: Vec<u32> = (0..5).collect();
/// let mut combinator = combinations(&sequence[..], 3);
///
/// let mut i = 0;
/// while let Some(combo) = combinator.next() {
/// 	let combination: Vec<&u32> = combo.collect();
///     println!("{}: {:?}", i, combination);
///     i += 1;
/// }
///
/// // Prints:
/// // 0: [0, 1, 2]
/// // 1: [0, 1, 3]
/// // 2: [0, 1, 4]
/// // 3: [0, 2, 3]
/// // 4: [0, 2, 4]
/// // 5: [0, 3, 4]
/// // 6: [1, 2, 3]
/// // 7: [1, 2, 4]
/// // 8: [1, 3, 4]
/// // 9: [2, 3, 4]
/// ```
///
pub fn combinations<'a, T>(seq: &'a [T], len: usize) -> Combinator<'a, T> {
    if len > seq.len() {
        panic!("Combination length longer than sequence ({} > {})",
               len,
               seq.len());
    }

    Combinator {
        seq: seq,
        indices: (0..len).collect(),
        inited: false,
    }
}

#[test]
fn all_combinations_generated() {
    // Original sequence
    let sequence: Vec<u32> = (0..4).collect();

    // Set of all combinations
    let combos: BTreeSet<BTreeSet<u32>> = [[0, 1, 2].iter().cloned().collect(),
                                           [0, 1, 3].iter().cloned().collect(),
                                           [0, 2, 3].iter().cloned().collect(),
                                           [1, 2, 3].iter().cloned().collect()]
                                              .iter()
                                              .cloned()
                                              .collect();

    let mut combinator = combinations(&sequence[..], 3);
    while let Some(combo) = combinator.next() {
        let c: BTreeSet<_> = combo.cloned().collect();
        assert!(combos.contains(&c),
                "{:?} does not contain {:?}",
                &combos,
                &c);
    }
}

#[test]
#[should_panic]
fn panics_on_invalid_combination_length() {
    let sequence: Vec<u32> = (0..4).collect();
    combinations(&sequence[..], sequence.len() + 1);
}
<commit_msg>Add crate-level documentation<commit_after>//! Small crate containing functionality for iterating over combinations of a sequence.
//!
//! See documentation of `combinations` function for usage details.

#[cfg(test)]
use std::collections::BTreeSet;

/// An non-standard iterator yielding combinations of elements from a sequence.
pub struct Combinator<'a, T>
    where T: 'a
{
    seq: &'a [T],
    indices: Vec<usize>,
    inited: bool,
}

impl<'a, 'b, T> Combinator<'a, T> {
    pub fn next(&'b mut self) -> Option<CombinationIter<'a, 'b, T>> {
        let seq_len = self.seq.len();
        let ref mut indices = self.indices;
        let k = indices.len();

        // First permutation is special cased
        if !self.inited {
            self.inited = true;

            return Some(CombinationIter {
                it: indices.iter(),
                seq: self.seq,
            });
        }

        for i in (0..k).rev() {
            // Try and increment this index
            indices[i] += 1;

            if indices[i] == seq_len - k + 1 + i {
                // Index has overflowed, try parent index
                continue;
            }

            // Reset child indices
            for j in i + 1..k {
                indices[j] = indices[j - 1] + 1;
            }

            return Some(CombinationIter {
                it: indices.iter(),
                seq: self.seq,
            });
        }

        return None;
    }
}

/// An `Iterator` yielding references to elements of a particular combination.
pub struct CombinationIter<'a, 'b, T>
    where T: 'a
{
    it: std::slice::Iter<'b, usize>,
    seq: &'a [T],
}

impl<'a, 'b, T> Iterator for CombinationIter<'a, 'b, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(i) = self.it.next() {
            Some(&self.seq[*i])
        } else {
            None
        }
    }
}

/// Returns a (non-standard) iterator yielding all combinations of length `len` from
/// the sequence `seq`.
///
/// Each combination is itself a (standard) `Iterator` yielding references to each element of the
/// combination.
///
/// # Panics
/// When attempting to iterate over combination lengths longer than the original sequence.
///
/// # Examples
///
/// ```
/// use combo::combinations;
///
/// let sequence: Vec<u32> = (0..5).collect();
/// let mut combinator = combinations(&sequence[..], 3);
///
/// let mut i = 0;
/// while let Some(combo) = combinator.next() {
/// 	let combination: Vec<&u32> = combo.collect();
///     println!("{}: {:?}", i, combination);
///     i += 1;
/// }
///
/// // Prints:
/// // 0: [0, 1, 2]
/// // 1: [0, 1, 3]
/// // 2: [0, 1, 4]
/// // 3: [0, 2, 3]
/// // 4: [0, 2, 4]
/// // 5: [0, 3, 4]
/// // 6: [1, 2, 3]
/// // 7: [1, 2, 4]
/// // 8: [1, 3, 4]
/// // 9: [2, 3, 4]
/// ```
///
pub fn combinations<'a, T>(seq: &'a [T], len: usize) -> Combinator<'a, T> {
    if len > seq.len() {
        panic!("Combination length longer than sequence ({} > {})",
               len,
               seq.len());
    }

    Combinator {
        seq: seq,
        indices: (0..len).collect(),
        inited: false,
    }
}

#[test]
fn all_combinations_generated() {
    // Original sequence
    let sequence: Vec<u32> = (0..4).collect();

    // Set of all combinations
    let combos: BTreeSet<BTreeSet<u32>> = [[0, 1, 2].iter().cloned().collect(),
                                           [0, 1, 3].iter().cloned().collect(),
                                           [0, 2, 3].iter().cloned().collect(),
                                           [1, 2, 3].iter().cloned().collect()]
                                              .iter()
                                              .cloned()
                                              .collect();

    let mut combinator = combinations(&sequence[..], 3);
    while let Some(combo) = combinator.next() {
        let c: BTreeSet<_> = combo.cloned().collect();
        assert!(combos.contains(&c),
                "{:?} does not contain {:?}",
                &combos,
                &c);
    }
}

#[test]
#[should_panic]
fn panics_on_invalid_combination_length() {
    let sequence: Vec<u32> = (0..4).collect();
    combinations(&sequence[..], sequence.len() + 1);
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate chrono;
extern crate uuid;

use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{channel, Receiver, Sender, SendError};
use std::thread::{Builder, JoinHandle};

use rustc_serialize::json::{Json, ToJson};
use uuid::Uuid;

pub struct Actor {
    join_handle: JoinHandle<()>,
    mailbox: Sender<Json>,
    name: String,
    uuid: Uuid,
}

impl Actor {
    fn new(
        join_handle: JoinHandle<()>,
        mailbox: Sender<Json>,
        name: String,
        uuid: Uuid,
    ) -> Actor {
        Actor {
            join_handle: join_handle,
            mailbox: mailbox,
            name: name,
            uuid: uuid,
        }
    }
}

pub struct Supervisor {
    actors: RwLock<HashMap<Uuid, Actor>>,
    name: String,
}

impl Supervisor {
    fn new(name: &str) -> Supervisor {
        Supervisor {
            actors: RwLock::new(HashMap::new()),
            name: name.to_string(),
        }
    }

    fn join(&self, pid : Uuid) -> Result<(), String> {
        match self.actors.write().unwrap().remove(&pid) {
            Some(actor) => {
                match actor.join_handle.join() {
                    Ok(_) => Ok(()),
                    Err(e) => Err("you really messed up".to_string()),
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn send_message(&self, pid: Uuid, message: Json) -> Result<(), String> {
        match self.actors.read().unwrap().get(&pid) {
            Some(actor) => {
                match actor.mailbox.send(message) {
                    Ok(_) => Ok(()),
                    Err(e) => { Err(e.to_string()) },
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn spawn<F>(&self, actor_name: &str, body: F) -> Result<Uuid, &str>
        where F : 'static + Send + Fn(Receiver<Json>) -> () {
        let pid = Uuid::new_v4();
        let (mailbox_sender, mailbox_receiver) = channel();
        let arc_body = Arc::new(Mutex::new(body));

        match self.actors.write() {
            Ok(mut actors) => {
                let actor_handle_result = Builder::new().name(pid.to_string()).spawn(move || {
                    arc_body.lock().unwrap()(mailbox_receiver);
                });

                match actor_handle_result {
                    Ok(actor_handle) => {
                        actors.insert(pid, Actor::new(
                            actor_handle,
                            mailbox_sender,
                            actor_name.to_string(),
                            pid,
                        ));

                        Ok(pid)
                    },
                    Err(e) => Err("boom"), // sigh
                }
            },
            Err(e) => Err("boom boom") // sigh
        }
    }
}

#[cfg(test)]
mod tests {
    use std::fs::{remove_file, File};
    use std::io::prelude::*;
    use std::sync::mpsc::{channel, Receiver, Sender};
    use std::thread;
    use chrono::*;
    use rustc_serialize::json::{Json, ToJson};
    use uuid::Uuid;
    use super::*;

    // spawn tests
    #[test]
    fn the_body_actor_callback_is_executed() {
        let supervisor = Supervisor::new("folks");
        let json_msg = "{\"hi\": \"friend\"}".to_json();
        let json_clone = json_msg.clone();
        let pid_bob: Uuid = supervisor.spawn(
            "Bob",
            |receiver| {
                let mut message_output_file = File::create("/tmp/bob-test.json").unwrap();
                message_output_file.write_all(receiver.recv().unwrap().to_string().as_bytes()).unwrap();
                ()
            }
        ).unwrap();

        supervisor.send_message(pid_bob, json_msg).unwrap();

        thread::sleep_ms(1001);
        let mut message_output_file = File::open("/tmp/bob-test.json").unwrap();
        let mut message_output = String::new();
        message_output_file.read_to_string(&mut message_output).unwrap();
        remove_file("/tmp/bob-test.json").unwrap();

        let actual_json = Json::from_str(&message_output).unwrap();
        assert_eq!(json_clone, actual_json);
    }

    // send_message tests
    #[test]
    fn error_is_returned_if_message_sent_for_pid_that_does_not_exist() {
        let supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn pid_can_be_used_to_send_message() {
        let supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { r.recv().unwrap(); () }
        ).unwrap();

        supervisor.send_message(pid, "{}".to_json()).unwrap();
    }

    // join tests
    #[test]
    fn pid_can_be_used_to_join_actor() {
        let supervisor = Supervisor::new("folks");
        let start_time = UTC::now();
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { thread::sleep_ms(1000); () }
        ).unwrap();
        assert!((start_time + Duration::milliseconds(1000)) > UTC::now());

        supervisor.join(pid).unwrap();

        assert!((start_time + Duration::milliseconds(1000)) < UTC::now());
    }

    #[test]
    fn joining_actor_makes_it_unreachable() {
        let supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { () }
        ).unwrap();
        supervisor.join(pid).unwrap();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn error_is_returned_if_joining_actor_that_does_not_exist() {
        let supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let join_result = supervisor.join(pid);

        match join_result {
            Ok(_) => panic!("Actor joined for non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }
}
<commit_msg>Better error messages<commit_after>extern crate rustc_serialize;
extern crate chrono;
extern crate uuid;

use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{channel, Receiver, Sender, SendError};
use std::thread::{Builder, JoinHandle};

use rustc_serialize::json::{Json, ToJson};
use uuid::Uuid;

pub struct Actor {
    join_handle: JoinHandle<()>,
    mailbox: Sender<Json>,
    name: String,
    uuid: Uuid,
}

impl Actor {
    fn new(
        join_handle: JoinHandle<()>,
        mailbox: Sender<Json>,
        name: String,
        uuid: Uuid,
    ) -> Actor {
        Actor {
            join_handle: join_handle,
            mailbox: mailbox,
            name: name,
            uuid: uuid,
        }
    }
}

pub struct Supervisor {
    actors: RwLock<HashMap<Uuid, Actor>>,
    name: String,
}

impl Supervisor {
    fn new(name: &str) -> Supervisor {
        Supervisor {
            actors: RwLock::new(HashMap::new()),
            name: name.to_string(),
        }
    }

    fn join(&self, pid : Uuid) -> Result<(), String> {
        match self.actors.write().unwrap().remove(&pid) {
            Some(actor) => {
                match actor.join_handle.join() {
                    Ok(_) => Ok(()),
                    Err(e) => {
                        if let Some(e) = e.downcast_ref::<&'static str>() {
                            Err(e.to_string())
                        } else {
                            Err(format!("Uknown error joining PID {}", pid.to_string()))
                        }
                    }
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn send_message(&self, pid: Uuid, message: Json) -> Result<(), String> {
        match self.actors.read().unwrap().get(&pid) {
            Some(actor) => {
                match actor.mailbox.send(message) {
                    Ok(_) => Ok(()),
                    Err(e) => { Err(e.to_string()) },
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn spawn<F>(&self, actor_name: &str, body: F) -> Result<Uuid, String>
        where F : 'static + Send + Fn(Receiver<Json>) -> () {
        let pid = Uuid::new_v4();
        let (mailbox_sender, mailbox_receiver) = channel();
        let arc_body = Arc::new(Mutex::new(body));

        match self.actors.write() {
            Ok(mut actors) => {
                let actor_handle_result = Builder::new().name(pid.to_string()).spawn(move || {
                    arc_body.lock().unwrap()(mailbox_receiver);
                });

                match actor_handle_result {
                    Ok(actor_handle) => {
                        actors.insert(pid, Actor::new(
                            actor_handle,
                            mailbox_sender,
                            actor_name.to_string(),
                            pid,
                        ));

                        Ok(pid)
                    },
                    Err(e) => Err(e.to_string()),
                }
            },
            Err(e) => Err(e.to_string())
        }
    }
}

#[cfg(test)]
mod tests {
    use std::fs::{remove_file, File};
    use std::io::prelude::*;
    use std::sync::mpsc::{channel, Receiver, Sender};
    use std::thread;
    use chrono::*;
    use rustc_serialize::json::{Json, ToJson};
    use uuid::Uuid;
    use super::*;

    // spawn tests
    #[test]
    fn the_body_actor_callback_is_executed() {
        let supervisor = Supervisor::new("folks");
        let json_msg = "{\"hi\": \"friend\"}".to_json();
        let json_clone = json_msg.clone();
        let pid_bob: Uuid = supervisor.spawn(
            "Bob",
            |receiver| {
                let mut message_output_file = File::create("/tmp/bob-test.json").unwrap();
                message_output_file.write_all(receiver.recv().unwrap().to_string().as_bytes()).unwrap();
                ()
            }
        ).unwrap();

        supervisor.send_message(pid_bob, json_msg).unwrap();

        thread::sleep_ms(1001);
        let mut message_output_file = File::open("/tmp/bob-test.json").unwrap();
        let mut message_output = String::new();
        message_output_file.read_to_string(&mut message_output).unwrap();
        remove_file("/tmp/bob-test.json").unwrap();

        let actual_json = Json::from_str(&message_output).unwrap();
        assert_eq!(json_clone, actual_json);
    }

    // send_message tests
    #[test]
    fn error_is_returned_if_message_sent_for_pid_that_does_not_exist() {
        let supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn pid_can_be_used_to_send_message() {
        let supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { r.recv().unwrap(); () }
        ).unwrap();

        supervisor.send_message(pid, "{}".to_json()).unwrap();
    }

    // join tests
    #[test]
    fn pid_can_be_used_to_join_actor() {
        let supervisor = Supervisor::new("folks");
        let start_time = UTC::now();
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { thread::sleep_ms(1000); () }
        ).unwrap();
        assert!((start_time + Duration::milliseconds(1000)) > UTC::now());

        supervisor.join(pid).unwrap();

        assert!((start_time + Duration::milliseconds(1000)) < UTC::now());
    }

    #[test]
    fn joining_actor_makes_it_unreachable() {
        let supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { () }
        ).unwrap();
        supervisor.join(pid).unwrap();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn error_is_returned_if_joining_actor_that_does_not_exist() {
        let supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let join_result = supervisor.join(pid);

        match join_result {
            Ok(_) => panic!("Actor joined for non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(generators, generator_trait, conservative_impl_trait, proc_macro)]

extern crate futures_await as futures;
extern crate crossbeam;

use std::ops::Generator;
use std::ops::GeneratorState;
use futures::prelude::*;
use crossbeam::sync::chase_lev;

struct AsyncGenerator<T>
where T: Generator
{
    generator: T,
    producer: chase_lev::Worker<GeneratorState<T::Yield, T::Return>>,
    consumer: chase_lev::Stealer<GeneratorState<T::Yield, T::Return>>
}

impl<T> AsyncGenerator<T>
where T: Generator
{
    fn new(generator: T) -> Self {
        let (mut producer, consumer) = chase_lev::deque();
        let mut async_gen = AsyncGenerator {
            generator: generator,
            producer: producer,
            consumer: consumer
        };
        async_gen.populate();
        async_gen
    }

    fn resume(&mut self) -> Option<T::Yield> {
        loop {
            match self.consumer.steal() {
                chase_lev::Steal::Data(data) => match data {
                    GeneratorState::Yielded(value) => return Some(value),
                    GeneratorState::Complete(_) => return None
                }
            }
        }
    }

    #[async]
    fn populate(&mut self) -> Result<(), ()> {
        loop {
            let next_item = self.generator.resume();
            self.producer.push(next_item);
            match next_item {
                GeneratorState::Complete(_) => break
            }
        }
        Ok(())
    }
}

trait IntoAsync<T>
where T: Generator
{
    fn into_async(self) -> AsyncGenerator<T>;
}

impl<T> IntoAsync<T> for T
where T: Generator
{
    fn into_async(self) -> AsyncGenerator<T> {
        AsyncGenerator::new(self)
    }
}

impl<T> Iterator for AsyncGenerator<T>
where T: Generator
{
    type Item = T::Yield;

    fn next(&mut self) -> Option<Self::Item> {
        return self.resume();
    }
}

#[cfg(test)]
mod tests {
    use std::ops::Generator;
    use IntoAsync;

    fn dummy_generator() -> impl Generator<Yield=u32, Return=()> {
        || {
            yield 1;
            yield 2;
            yield 3;
            return;
        }
    }

    #[test]
    fn it_works() {
        let test : Vec<_> = dummy_generator().into_async().collect();

        assert_eq!(vec![1u32, 2, 3], test);
    }
}
<commit_msg>Infinite loop<commit_after>#![feature(generators, generator_trait, conservative_impl_trait, proc_macro)]

extern crate futures_await as futures;
extern crate crossbeam;

use std::ops::Generator;
use std::ops::GeneratorState;
use futures::prelude::*;
use crossbeam::sync::chase_lev;

struct AsyncGenerator<T>
where T: Generator
{
    consumer: chase_lev::Stealer<GeneratorState<T::Yield, T::Return>>
}

impl<T> AsyncGenerator<T>
where T: Generator + 'static
{
    fn new(generator: T) -> Self {
        let (producer, consumer) = chase_lev::deque();
        populate(generator, producer);
        AsyncGenerator { consumer: consumer }
    }

    fn resume(&mut self) -> Option<T::Yield> {
        loop {
            match self.consumer.steal() {
                chase_lev::Steal::Data(data) => match data {
                    GeneratorState::Yielded(value) => return Some(value),
                    GeneratorState::Complete(_) => return None
                },
                chase_lev::Steal::Empty => continue,
                chase_lev::Steal::Abort => return None
            }
        }
    }
}

#[async]
fn populate<T>(mut generator: T, producer: chase_lev::Worker<GeneratorState<T::Yield, T::Return>>) -> Result<(), ()>
where T: Generator + 'static
{
    let mut abort = false;
    while !abort {
        let next_item = generator.resume();
        match next_item {
            GeneratorState::Complete(_) => abort = true,
            GeneratorState::Yielded(_) => abort = false
        }
        producer.push(next_item);
    }
    Ok(())
}

trait IntoAsync<T>
where T: Generator
{
    fn into_async(self) -> AsyncGenerator<T>;
}

impl<T> IntoAsync<T> for T
where T: Generator + 'static
{
    fn into_async(self) -> AsyncGenerator<T> {
        AsyncGenerator::new(self)
    }
}

impl<T> Iterator for AsyncGenerator<T>
where T: Generator + 'static
{
    type Item = T::Yield;

    fn next(&mut self) -> Option<Self::Item> {
        return self.resume();
    }
}

#[cfg(test)]
mod tests {
    use std::ops::Generator;
    use IntoAsync;

    fn dummy_generator() -> impl Generator<Yield=u32, Return=()> {
        || {
            yield 1;
            yield 2;
            yield 3;
            return;
        }
    }

    #[test]
    fn it_works() {
        let test : Vec<_> = dummy_generator().into_async().collect();

        assert_eq!(vec![1u32, 2, 3], test);
    }
}
<|endoftext|>


<commit_before>pub mod topic;

pub fn parse_input(s: &str) -> Result<(&str, u8), &str> {
    let mut iter = s.split(",");
    match (iter.next(), iter.next()) {
        (Some(topic), Some(n)) => Ok((topic, n)),
        _ => Err("Bad input")
    }.and_then(|(topic, n)| {
        n.trim()
            .parse::<u8>()
            .map(|num| { (topic, num) })
            .or(Err("Bad input"))
    })
}

#[test]
fn should_parse_valid_input() {

    let (topic, num) = parse_input("Dance, 42").unwrap();

    assert_eq!(num, 42);
    assert_eq!(topic, "Dance");
}

#[test]
fn should_fail_to_parse_non_number(){

    let result = parse_input("Comom, Lomom");

    assert_eq!(result, Err("Bad input"));
}

#[test]
fn should_fail_to_parse_missing_comma(){

    let result = parse_input("Toldom Acjdul");

    assert_eq!(result, Err("Bad input"));
}
<commit_msg>EM: refactoring parsing code<commit_after>pub mod topic;

pub fn parse_input(s: &str) -> Result<(&str, u8), &str> {
    let mut iter = s.split(",");
    match (iter.next(), iter.next()) {
        (Some(topic), Some(n)) => Ok((topic, n)),
        _ => Err("Bad input")
    }.and_then(parse_tuple)
}

fn parse_tuple<'a>(tuple: (&'a str, &str)) -> Result<(&'a str, u8), &'a str> {
    let (topic, n) = tuple;
    n.trim()
        .parse()
        .map(|num| { (topic, num) })
        .or(Err("Bad input"))
}

#[test]
fn should_parse_valid_input() {

    let (topic, num) = parse_input("Dance, 42").unwrap();

    assert_eq!(num, 42);
    assert_eq!(topic, "Dance");
}

#[test]
fn should_fail_to_parse_non_number(){

    let result = parse_input("Comom, Lomom");

    assert_eq!(result, Err("Bad input"));
}

#[test]
fn should_fail_to_parse_missing_comma(){

    let result = parse_input("Toldom Acjdul");

    assert_eq!(result, Err("Bad input"));
}
<|endoftext|>


<commit_before>
#![feature(macro_rules, phase)]

extern crate syntax;
extern crate rustc;
extern crate graphics;
extern crate piston;
extern crate opengl_graphics;
extern crate serialize;
extern crate freetype;

pub use Widget = widget::Widget;
pub use Color = color::Color;
pub use Point = point::Point;
pub use UIContext = ui_context::UIContext;

pub mod macros;

pub mod button;
pub mod color;
pub mod glyph_cache;
pub mod label;
pub mod mouse_state;
pub mod point;
pub mod rectangle;
pub mod slider;
pub mod toggle;
pub mod ui_context;
pub mod utils;
pub mod widget;

<commit_msg>Removed unnecessary crates from lib.rs<commit_after>
#![feature(macro_rules, phase)]

extern crate graphics;
extern crate piston;
extern crate opengl_graphics;
extern crate serialize;
extern crate freetype;

pub use Widget = widget::Widget;
pub use Color = color::Color;
pub use Point = point::Point;
pub use UIContext = ui_context::UIContext;

pub mod macros;

pub mod button;
pub mod color;
pub mod glyph_cache;
pub mod label;
pub mod mouse_state;
pub mod point;
pub mod rectangle;
pub mod slider;
pub mod toggle;
pub mod ui_context;
pub mod utils;
pub mod widget;

<|endoftext|>


<commit_before>//! This is a small crate for the [AnyBar](https://github.com/tonsky/AnyBar).
//!
//! # Examples
//! The functioning of this crate is pretty simple. These are the most use cases:
//!
//! ## Using the default port
//! ```
//! # use anybar::*;
//! // create a new AnyBar instance connected to the default port
//! let mut bar = Anybar::default();
//!
//! // set the color
//! bar.set_color(Color::Red).unwrap();
//! ```
//!
//! ## Using a separate port
//! ```
//! # use anybar::*;
//! // Anybar::new() takes the Anybar port as parameter
//! let mut custom_bar = Anybar::new(1708);
//! custom_bar.set_color(Color::Exclamation).unwrap();
//! ```
//!
//! ## Additional information
//! ```
//! # use anybar::*;
//! let mut bar = Anybar::default();
//!
//! // after instantiation, the last color is None
//! assert!(bar.color.is_none());
//!
//! bar.set_color(Color::Red).unwrap();
//! // the last color now contains a value
//! // assert_eq!(bar.color.unwrap(), Color::Red);
//! ```
//!
//! Note that the value of `bar.color` does not necessarily represent the real color
//! displayed at the moment, depending on whether you have something or someone else messing
//! with your AnyBar simultaneously.
//!
//! # Note
//! The AnyBar itself does not provide any information on whether the sent command was executed
//! successfully, so the lib will only return an error if it was not able to bind a UDP socket.
//!

use std::net;

/// The Anybar handle.
pub struct Anybar {
    /// The UDP Port the Anybar is connected to
    pub port: u16,
    /// The last color that has been set.
    ///
    /// When no color has been set yet, color is `None`.
    pub color: Option<Color>,
}

/// The different colors supported by AnyBar.
pub enum Color {
    /// White dot
    White,
    /// Red dot
    Red,
    /// Orange dot
    Orange,
    /// Yellow dot
    Yellow,
    /// Green dot
    Green,
    /// Cyan dot
    Cyan,
    /// Blue dot
    Blue,
    /// Purple dot
    Purple,
    /// Black dot; Has a white frame in _dark_ mode
    Black,
    /// Question mark
    Question,
    /// White exclamation mark on red ground
    Exclamation,
}

impl Anybar {
    /// Create a new Anybar instance, connected to the given UDP port.
    ///
    /// `port` may be any port between 0 and 6553.
    ///
    /// # Examples
    ///
    /// ```
    /// # use anybar::*;
    /// let custom_bar = Anybar::new(1708).unwrap();
    ///
    /// assert_eq!(custom_bar.port, 1708);
    /// ```
    pub fn new(port: u16) -> Result<Anybar, String> {
        if port > 6553 {
            Err(format!("The port {} is not between 0 and 6553!", port))
        } else {
            Ok(Anybar{port:port, color:None})
        }
    }

    fn parse_color(color: &Color) -> &'static [u8] {
        use Color::*;
        match *color {
            White       => b"white",
            Red         => b"red",
            Orange      => b"orange",
            Yellow      => b"yellow",
            Green       => b"green",
            Cyan        => b"cyan",
            Blue        => b"blue",
            Purple      => b"purple",
            Black       => b"black",
            Question    => b"question",
            Exclamation => b"exclamation",
        }
    }

    fn socket(ip: &str, port: u16) -> Result<net::UdpSocket, std::io::Error> {
        net::UdpSocket::bind((ip, port))
    }

    /// Set a new color.
    ///
    /// The function returns a `ResultType` which will contain a `std::io::Error` when the UDP socket can't be bound.
    pub fn set_color(&mut self, color: Color) -> Result<(), std::io::Error> {
        let message = Anybar::parse_color(&color);

        let socket = try!(Anybar::socket("127.0.0.1", 0));

        let _ = socket.send_to(&message, ("127.0.0.1", self.port));
        drop(socket);

        self.color = Some(color);
        Ok(())
    }

    /// Sends the quit signal to the Anybar and takes ownership of the object.
    ///
    /// _This is an experimental feature of AnyBar._ Since the AnyBar will quit during the
    /// execution of this function, it takes the ownership of `self`,
    /// which will be dropped when this function returns.
    ///
    /// The function returns a `ResultType` which will contain a `std::io::Error` when the UDP socket can't be bound.
    ///
    /// # Example
    /// ```ignore
    /// # use anybar::*;
    /// let mut bar = Anybar::default();
    ///
    /// // do stuff...
    ///
    /// bar.quit().unwrap();
    ///
    /// bar.set_color(Color::White).unwrap();  // this won't work, bar has been moved
    /// ```
    pub fn quit(self) -> Result<(), std::io::Error> {
        let socket = try!(Anybar::socket("127.0.0.1", 0));

        let _ = socket.send_to(b"quit", ("127.0.0.1", self.port));
        drop(socket);
        Ok(())
    }
}

/// Instanciates the default AnyBar, connected to the Port `1738`.
///
/// ```
/// # use anybar::*;
/// let bar = Anybar::default();
/// assert_eq!(bar.port, 1738);
/// ```
impl Default for Anybar {
    fn default() -> Anybar {
        Anybar{port:1738, color:None}
    }
}
<commit_msg>try more!<commit_after>//! This is a small crate for the [AnyBar](https://github.com/tonsky/AnyBar).
//!
//! # Examples
//! The functioning of this crate is pretty simple. These are the most use cases:
//!
//! ## Using the default port
//! ```
//! # use anybar::*;
//! // create a new AnyBar instance connected to the default port
//! let mut bar = Anybar::default();
//!
//! // set the color
//! bar.set_color(Color::Red).unwrap();
//! ```
//!
//! ## Using a separate port
//! ```
//! # use anybar::*;
//! // Anybar::new() takes the Anybar port as parameter
//! let mut custom_bar = Anybar::new(1708);
//! custom_bar.set_color(Color::Exclamation).unwrap();
//! ```
//!
//! ## Additional information
//! ```
//! # use anybar::*;
//! let mut bar = Anybar::default();
//!
//! // after instantiation, the last color is None
//! assert!(bar.color.is_none());
//!
//! bar.set_color(Color::Red).unwrap();
//! // the last color now contains a value
//! // assert_eq!(bar.color.unwrap(), Color::Red);
//! ```
//!
//! Note that the value of `bar.color` does not necessarily represent the real color
//! displayed at the moment, depending on whether you have something or someone else messing
//! with your AnyBar simultaneously.
//!
//! # Note
//! The AnyBar itself does not provide any information on whether the sent command was executed
//! successfully, so the lib will only return an error if it was not able to bind a UDP socket.
//!

use std::net;

/// The Anybar handle.
pub struct Anybar {
    /// The UDP Port the Anybar is connected to
    pub port: u16,
    /// The last color that has been set.
    ///
    /// When no color has been set yet, color is `None`.
    pub color: Option<Color>,
}

/// The different colors supported by AnyBar.
pub enum Color {
    /// White dot
    White,
    /// Red dot
    Red,
    /// Orange dot
    Orange,
    /// Yellow dot
    Yellow,
    /// Green dot
    Green,
    /// Cyan dot
    Cyan,
    /// Blue dot
    Blue,
    /// Purple dot
    Purple,
    /// Black dot; Has a white frame in _dark_ mode
    Black,
    /// Question mark
    Question,
    /// White exclamation mark on red ground
    Exclamation,
}

impl Anybar {
    /// Create a new Anybar instance, connected to the given UDP port.
    ///
    /// `port` may be any port between 0 and 6553.
    ///
    /// # Examples
    ///
    /// ```
    /// # use anybar::*;
    /// let custom_bar = Anybar::new(1708).unwrap();
    ///
    /// assert_eq!(custom_bar.port, 1708);
    /// ```
    pub fn new(port: u16) -> Result<Anybar, String> {
        if port > 6553 {
            Err(format!("The port {} is not between 0 and 6553!", port))
        } else {
            Ok(Anybar{port:port, color:None})
        }
    }

    fn parse_color(color: &Color) -> &'static [u8] {
        use Color::*;
        match *color {
            White       => b"white",
            Red         => b"red",
            Orange      => b"orange",
            Yellow      => b"yellow",
            Green       => b"green",
            Cyan        => b"cyan",
            Blue        => b"blue",
            Purple      => b"purple",
            Black       => b"black",
            Question    => b"question",
            Exclamation => b"exclamation",
        }
    }

    fn socket(ip: &str, port: u16) -> Result<net::UdpSocket, std::io::Error> {
        net::UdpSocket::bind((ip, port))
    }

    /// Set a new color.
    ///
    /// The function returns a `ResultType` which will contain a `std::io::Error` when the UDP socket can't be bound.
    pub fn set_color(&mut self, color: Color) -> Result<(), std::io::Error> {
        let message = Anybar::parse_color(&color);

        Anybar::socket("127.0.0.1", 0)?
            .send_to(&message, ("127.0.0.1", self.port))?;

        self.color = Some(color);
        Ok(())
    }

    /// Sends the quit signal to the Anybar and takes ownership of the object.
    ///
    /// _This is an experimental feature of AnyBar._ Since the AnyBar will quit during the
    /// execution of this function, it takes the ownership of `self`,
    /// which will be dropped when this function returns.
    ///
    /// The function returns a `ResultType` which will contain a `std::io::Error` when the UDP socket can't be bound.
    ///
    /// # Example
    /// ```ignore
    /// # use anybar::*;
    /// let mut bar = Anybar::default();
    ///
    /// // do stuff...
    ///
    /// bar.quit().unwrap();
    ///
    /// bar.set_color(Color::White).unwrap();  // this won't work, bar has been moved
    /// ```
    pub fn quit(self) -> Result<(), std::io::Error> {
        Anybar::socket("127.0.0.1", 0)?
            .send_to(b"quit", ("127.0.0.1", self.port))?;
        Ok(())
    }
}

/// Instanciates the default AnyBar, connected to the Port `1738`.
///
/// ```
/// # use anybar::*;
/// let bar = Anybar::default();
/// assert_eq!(bar.port, 1738);
/// ```
impl Default for Anybar {
    fn default() -> Anybar {
        Anybar{port:1738, color:None}
    }
}
<|endoftext|>


<commit_before>//! Rustic bindings to [libnotify](https://developer.gnome.org/libnotify/)
//!
//! ```rust
//! extern crate libnotify;
//!
//! fn main() {
//!     // Create a libnotify context
//!     let notify = libnotify::Context::new("myapp").unwrap();
//!     // Create a new notification and show it
//!     let n = notify.new_notification("Summary",
//!                                     Some("Optional Body"),
//!                                     None).unwrap();
//!     n.show().unwrap();
//!     // You can also use the .show() convenience method on the context
//!     notify.show("I am another notification", None, None).unwrap();
//! }
//!
//! ```

#![warn(missing_docs)]

extern crate gdk_pixbuf;
extern crate gdk_pixbuf_sys;
extern crate glib;
extern crate glib_sys;
extern crate gtypes;
extern crate libnotify_sys as sys;

use gdk_pixbuf_sys::GdkPixbuf;
use glib::translate::*;
use gtypes::{TRUE, FALSE};
use std::error::Error;
use std::ffi::{self, CStr, CString};
use std::fmt;
use std::marker::PhantomData;
use std::os::raw::c_int;

/// The urgency level of the notification.
pub enum Urgency {
    /// Low urgency. Used for unimportant notifications.
    Low,
    /// Normal urgency. Used for most standard notifications.
    Normal,
    /// Critical urgency. Used for very important notifications.
    Critical,
}

impl From<sys::NotifyUrgency> for Urgency {
    fn from(urgency: sys::NotifyUrgency) -> Urgency {
        match urgency {
            sys::NotifyUrgency::NotifyUrgencyLow => Urgency::Low,
            sys::NotifyUrgency::NotifyUrgencyNormal => Urgency::Normal,
            sys::NotifyUrgency::NotifyUrgencyCritical => Urgency::Critical,
        }
    }
}

impl From<Urgency> for sys::NotifyUrgency {
    fn from(urgency: Urgency) -> sys::NotifyUrgency {
        match urgency {
            Urgency::Low => sys::NotifyUrgency::NotifyUrgencyLow,
            Urgency::Normal => sys::NotifyUrgency::NotifyUrgencyNormal,
            Urgency::Critical => sys::NotifyUrgency::NotifyUrgencyCritical,
        }
    }
}

/// Error that can happen on context creation
#[derive(Debug)]
pub enum ContextCreationError {
    /// Context already exists.
    AlreadyExists,
    /// Failed to initialize libnotify.
    InitError,
    /// A nul byte was found in the provided string.
    NulError(ffi::NulError),
}

impl fmt::Display for ContextCreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use ContextCreationError::*;
        match *self {
            AlreadyExists => write!(f, "A Libnotify context already exists."),
            InitError => write!(f, "Failed to initialize libnotify."),
            NulError(ref e) => write!(f, "{}", e),
        }
    }
}

impl From<ffi::NulError> for ContextCreationError {
    fn from(src: ffi::NulError) -> Self {
        ContextCreationError::NulError(src)
    }
}

#[derive(Debug)]
/// An error that can happen when attempting to create a notification.
pub enum NotificationCreationError {
    /// A nul byte was found in the provided string.
    NulError(ffi::NulError),
    /// An unknown error happened.
    Unknown,
    /// Invalid parameter passed to a glib function
    InvalidParameter,
}

impl fmt::Display for NotificationCreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use NotificationCreationError::*;
        match *self {
            NulError(ref e) => write!(f, "{}", e),
            Unknown => write!(f, "Unknown error"),
            InvalidParameter => write!(f, "An invalid parameter was passed"),
        }
    }
}

impl From<ffi::NulError> for NotificationCreationError {
    fn from(src: ffi::NulError) -> Self {
        NotificationCreationError::NulError(src)
    }
}

impl Error for NotificationCreationError {
    fn description(&self) -> &str {
        "notification creation error"
    }
}

/// The context which within libnotify operates.
///
/// Only one context can exist at a time.
pub struct Context;

impl Context {
    /// Create a new context
    ///
    /// Arguments:
    ///
    /// - app_name: The name of the application using the context
    pub fn new(app_name: &str) -> Result<Context, ContextCreationError> {
        unsafe {
            if sys::notify_is_initted() == TRUE {
                return Err(ContextCreationError::AlreadyExists);
            }
            let app_name = try!(CString::new(app_name));
            if sys::notify_init(app_name.as_ptr()) == FALSE {
                return Err(ContextCreationError::InitError);
            }
        }
        Ok(Context)
    }

    /// Creates a new Notification.
    ///
    /// Arguments:
    ///
    /// - summary: Required summary text
    /// - body: Optional body text
    /// - icon: Optional icon theme icon name or filename
    pub fn new_notification
        (&self,
         summary: &str,
         body: Option<&str>,
         icon: Option<&str>)
         -> Result<Notification, NotificationCreationError> {
        let summary = try!(CString::new(summary));
        let body = match body {
            Some(body) => Some(try!(CString::new(body))),
            None => None,
        };
        let body_ptr = match body {
            Some(ref body) => body.as_ptr(),
            None => std::ptr::null(),
        };
        let icon = match icon {
            Some(icon) => Some(try!(CString::new(icon))),
            None => None,
        };
        let icon_ptr = match icon {
            Some(ref icon) => icon.as_ptr(),
            None => std::ptr::null(),
        };

        unsafe {
            let n = sys::notify_notification_new(summary.as_ptr(),
                                                 body_ptr,
                                                 icon_ptr);
            if n.is_null() {
                return Err(NotificationCreationError::Unknown);
            }

            Ok(Notification {
                   handle: n,
                   _phantom: PhantomData,
               })
        }
    }

    /// Show a notification.
    ///
    /// This is a convenience method that creates a new notification,
    /// and shows it in one step.
    pub fn show(&self,
                summary: &str,
                body: Option<&str>,
                icon: Option<&str>)
                -> Result<(), Box<Error>> {
        let notif = try!(self.new_notification(summary, body, icon));
        try!(notif.show());
        Ok(())
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            sys::notify_uninit();
        }
    }
}

/// A passive pop-up notification
pub struct Notification<'a> {
    handle: *mut sys::NotifyNotification,
    _phantom: PhantomData<&'a Context>,
}

impl<'a> Notification<'a> {
    /// Tells the notification server to display the notification
    /// on the screen.
    pub fn show(&'a self) -> Result<(), NotificationShowError> {
        unsafe {
            let mut err: *mut glib_sys::GError = std::ptr::null_mut();
            sys::notify_notification_show(self.handle, &mut err);
            if !err.is_null() {
                let result = Err(NotificationShowError {
                                     message: CStr::from_ptr((*err).message)
                                         .to_string_lossy()
                                         .into_owned(),
                                 });
                glib_sys::g_error_free(err);
                return result;
            }
            Ok(())
        }
    }

    /// Set the notification timeout. Note that the server might ignore
    /// the timeout.
    pub fn set_notification_timeout(&self, timeout: i32) {
        let _timeout: c_int = From::from(timeout);

        unsafe { sys::notify_notification_set_timeout(self.handle, _timeout) }
    }

    /// Updates the notification text and icon. This won't send the update
    /// out and display it on the screen. For that, you will need to
    /// call `.show()`.
    pub fn update(&self,
                  summary: &str,
                  body: Option<&str>,
                  icon: Option<&str>)
                  -> Result<(), NotificationCreationError> {
        let summary = try!(CString::new(summary));
        let body = match body {
            Some(body) => Some(try!(CString::new(body))),
            None => None,
        };
        let body_ptr = match body {
            Some(ref body) => body.as_ptr(),
            None => std::ptr::null(),
        };
        let icon = match icon {
            Some(icon) => Some(try!(CString::new(icon))),
            None => None,
        };
        let icon_ptr = match icon {
            Some(ref icon) => icon.as_ptr(),
            None => std::ptr::null(),
        };

        unsafe {
            let b = sys::notify_notification_update(self.handle,
                                                    summary.as_ptr(),
                                                    body_ptr,
                                                    icon_ptr);
            if b == FALSE {
                return Err(NotificationCreationError::InvalidParameter);
            }
        }

        return Ok(());
    }

    /// Sets a hint for `key` with value `value`. If value is `None`,
    /// then key is unset.
    pub fn set_hint(&self,
                    key: &str,
                    value: Option<glib::variant::Variant>)
                    -> Result<(), NotificationCreationError> {
        let key = try!(CString::new(key));

        let gvalue: *mut glib_sys::GVariant = {
            match value {
                Some(ref value) => value.to_glib_none().0,
                None => std::ptr::null_mut(),
            }
        };

        unsafe {
            sys::notify_notification_set_hint(self.handle, key.as_ptr(), gvalue)
        }

        return Ok(());
    }

    /// Sets the category of this notification. This can be used by the
    /// notification server to filter or display the data in a certain way.
    pub fn set_category(&self, category: &str) -> Result<(), NotificationCreationError> {
        let category = try!(CString::new(category));
        unsafe {
            sys::notify_notification_set_category(self.handle,
                                                   category.as_ptr());
        }

        return Ok(());
    }

    /// Sets the urgency level of this notification.
    pub fn set_urgency(&self, urgency: Urgency) {
        let urgency: sys::NotifyUrgency = From::from(urgency);

        unsafe {
            sys::notify_notification_set_urgency(self.handle,
                                             urgency);
        }
    }

    /// Sets the image in the notification from a Pixbuf.
    pub fn set_image_from_pixbuf(&self, pixbuf: &gdk_pixbuf::Pixbuf) {
        let pixbuf: *mut GdkPixbuf = pixbuf.to_glib_none().0;

        unsafe {
            sys::notify_notification_set_image_from_pixbuf(self.handle,
                                                            pixbuf);
        }
    }
}

/// An error that can happen when attempting to show a notification.
#[derive(Debug)]
pub struct NotificationShowError {
    message: String,
}

impl fmt::Display for NotificationShowError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error showing notification: {}", self.message)
    }
}

impl Error for NotificationShowError {
    fn description(&self) -> &str {
        "notification show error"
    }
}
<commit_msg>Add Notification::clear_hints()<commit_after>//! Rustic bindings to [libnotify](https://developer.gnome.org/libnotify/)
//!
//! ```rust
//! extern crate libnotify;
//!
//! fn main() {
//!     // Create a libnotify context
//!     let notify = libnotify::Context::new("myapp").unwrap();
//!     // Create a new notification and show it
//!     let n = notify.new_notification("Summary",
//!                                     Some("Optional Body"),
//!                                     None).unwrap();
//!     n.show().unwrap();
//!     // You can also use the .show() convenience method on the context
//!     notify.show("I am another notification", None, None).unwrap();
//! }
//!
//! ```

#![warn(missing_docs)]

extern crate gdk_pixbuf;
extern crate gdk_pixbuf_sys;
extern crate glib;
extern crate glib_sys;
extern crate gtypes;
extern crate libnotify_sys as sys;

use gdk_pixbuf_sys::GdkPixbuf;
use glib::translate::*;
use gtypes::{TRUE, FALSE};
use std::error::Error;
use std::ffi::{self, CStr, CString};
use std::fmt;
use std::marker::PhantomData;
use std::os::raw::c_int;

/// The urgency level of the notification.
pub enum Urgency {
    /// Low urgency. Used for unimportant notifications.
    Low,
    /// Normal urgency. Used for most standard notifications.
    Normal,
    /// Critical urgency. Used for very important notifications.
    Critical,
}

impl From<sys::NotifyUrgency> for Urgency {
    fn from(urgency: sys::NotifyUrgency) -> Urgency {
        match urgency {
            sys::NotifyUrgency::NotifyUrgencyLow => Urgency::Low,
            sys::NotifyUrgency::NotifyUrgencyNormal => Urgency::Normal,
            sys::NotifyUrgency::NotifyUrgencyCritical => Urgency::Critical,
        }
    }
}

impl From<Urgency> for sys::NotifyUrgency {
    fn from(urgency: Urgency) -> sys::NotifyUrgency {
        match urgency {
            Urgency::Low => sys::NotifyUrgency::NotifyUrgencyLow,
            Urgency::Normal => sys::NotifyUrgency::NotifyUrgencyNormal,
            Urgency::Critical => sys::NotifyUrgency::NotifyUrgencyCritical,
        }
    }
}

/// Error that can happen on context creation
#[derive(Debug)]
pub enum ContextCreationError {
    /// Context already exists.
    AlreadyExists,
    /// Failed to initialize libnotify.
    InitError,
    /// A nul byte was found in the provided string.
    NulError(ffi::NulError),
}

impl fmt::Display for ContextCreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use ContextCreationError::*;
        match *self {
            AlreadyExists => write!(f, "A Libnotify context already exists."),
            InitError => write!(f, "Failed to initialize libnotify."),
            NulError(ref e) => write!(f, "{}", e),
        }
    }
}

impl From<ffi::NulError> for ContextCreationError {
    fn from(src: ffi::NulError) -> Self {
        ContextCreationError::NulError(src)
    }
}

#[derive(Debug)]
/// An error that can happen when attempting to create a notification.
pub enum NotificationCreationError {
    /// A nul byte was found in the provided string.
    NulError(ffi::NulError),
    /// An unknown error happened.
    Unknown,
    /// Invalid parameter passed to a glib function
    InvalidParameter,
}

impl fmt::Display for NotificationCreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use NotificationCreationError::*;
        match *self {
            NulError(ref e) => write!(f, "{}", e),
            Unknown => write!(f, "Unknown error"),
            InvalidParameter => write!(f, "An invalid parameter was passed"),
        }
    }
}

impl From<ffi::NulError> for NotificationCreationError {
    fn from(src: ffi::NulError) -> Self {
        NotificationCreationError::NulError(src)
    }
}

impl Error for NotificationCreationError {
    fn description(&self) -> &str {
        "notification creation error"
    }
}

/// The context which within libnotify operates.
///
/// Only one context can exist at a time.
pub struct Context;

impl Context {
    /// Create a new context
    ///
    /// Arguments:
    ///
    /// - app_name: The name of the application using the context
    pub fn new(app_name: &str) -> Result<Context, ContextCreationError> {
        unsafe {
            if sys::notify_is_initted() == TRUE {
                return Err(ContextCreationError::AlreadyExists);
            }
            let app_name = try!(CString::new(app_name));
            if sys::notify_init(app_name.as_ptr()) == FALSE {
                return Err(ContextCreationError::InitError);
            }
        }
        Ok(Context)
    }

    /// Creates a new Notification.
    ///
    /// Arguments:
    ///
    /// - summary: Required summary text
    /// - body: Optional body text
    /// - icon: Optional icon theme icon name or filename
    pub fn new_notification
        (&self,
         summary: &str,
         body: Option<&str>,
         icon: Option<&str>)
         -> Result<Notification, NotificationCreationError> {
        let summary = try!(CString::new(summary));
        let body = match body {
            Some(body) => Some(try!(CString::new(body))),
            None => None,
        };
        let body_ptr = match body {
            Some(ref body) => body.as_ptr(),
            None => std::ptr::null(),
        };
        let icon = match icon {
            Some(icon) => Some(try!(CString::new(icon))),
            None => None,
        };
        let icon_ptr = match icon {
            Some(ref icon) => icon.as_ptr(),
            None => std::ptr::null(),
        };

        unsafe {
            let n = sys::notify_notification_new(summary.as_ptr(),
                                                 body_ptr,
                                                 icon_ptr);
            if n.is_null() {
                return Err(NotificationCreationError::Unknown);
            }

            Ok(Notification {
                   handle: n,
                   _phantom: PhantomData,
               })
        }
    }

    /// Show a notification.
    ///
    /// This is a convenience method that creates a new notification,
    /// and shows it in one step.
    pub fn show(&self,
                summary: &str,
                body: Option<&str>,
                icon: Option<&str>)
                -> Result<(), Box<Error>> {
        let notif = try!(self.new_notification(summary, body, icon));
        try!(notif.show());
        Ok(())
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            sys::notify_uninit();
        }
    }
}

/// A passive pop-up notification
pub struct Notification<'a> {
    handle: *mut sys::NotifyNotification,
    _phantom: PhantomData<&'a Context>,
}

impl<'a> Notification<'a> {
    /// Tells the notification server to display the notification
    /// on the screen.
    pub fn show(&'a self) -> Result<(), NotificationShowError> {
        unsafe {
            let mut err: *mut glib_sys::GError = std::ptr::null_mut();
            sys::notify_notification_show(self.handle, &mut err);
            if !err.is_null() {
                let result = Err(NotificationShowError {
                                     message: CStr::from_ptr((*err).message)
                                         .to_string_lossy()
                                         .into_owned(),
                                 });
                glib_sys::g_error_free(err);
                return result;
            }
            Ok(())
        }
    }

    /// Set the notification timeout. Note that the server might ignore
    /// the timeout.
    pub fn set_notification_timeout(&self, timeout: i32) {
        let _timeout: c_int = From::from(timeout);

        unsafe { sys::notify_notification_set_timeout(self.handle, _timeout) }
    }

    /// Updates the notification text and icon. This won't send the update
    /// out and display it on the screen. For that, you will need to
    /// call `.show()`.
    pub fn update(&self,
                  summary: &str,
                  body: Option<&str>,
                  icon: Option<&str>)
                  -> Result<(), NotificationCreationError> {
        let summary = try!(CString::new(summary));
        let body = match body {
            Some(body) => Some(try!(CString::new(body))),
            None => None,
        };
        let body_ptr = match body {
            Some(ref body) => body.as_ptr(),
            None => std::ptr::null(),
        };
        let icon = match icon {
            Some(icon) => Some(try!(CString::new(icon))),
            None => None,
        };
        let icon_ptr = match icon {
            Some(ref icon) => icon.as_ptr(),
            None => std::ptr::null(),
        };

        unsafe {
            let b = sys::notify_notification_update(self.handle,
                                                    summary.as_ptr(),
                                                    body_ptr,
                                                    icon_ptr);
            if b == FALSE {
                return Err(NotificationCreationError::InvalidParameter);
            }
        }

        return Ok(());
    }

    /// Sets a hint for `key` with value `value`. If value is `None`,
    /// then key is unset.
    pub fn set_hint(&self,
                    key: &str,
                    value: Option<glib::variant::Variant>)
                    -> Result<(), NotificationCreationError> {
        let key = try!(CString::new(key));

        let gvalue: *mut glib_sys::GVariant = {
            match value {
                Some(ref value) => value.to_glib_none().0,
                None => std::ptr::null_mut(),
            }
        };

        unsafe {
            sys::notify_notification_set_hint(self.handle, key.as_ptr(), gvalue)
        }

        return Ok(());
    }

    /// Sets the category of this notification. This can be used by the
    /// notification server to filter or display the data in a certain way.
    pub fn set_category(&self, category: &str) -> Result<(), NotificationCreationError> {
        let category = try!(CString::new(category));
        unsafe {
            sys::notify_notification_set_category(self.handle,
                                                   category.as_ptr());
        }

        return Ok(());
    }

    /// Sets the urgency level of this notification.
    pub fn set_urgency(&self, urgency: Urgency) {
        let urgency: sys::NotifyUrgency = From::from(urgency);

        unsafe {
            sys::notify_notification_set_urgency(self.handle,
                                             urgency);
        }
    }

    /// Sets the image in the notification from a Pixbuf.
    pub fn set_image_from_pixbuf(&self, pixbuf: &gdk_pixbuf::Pixbuf) {
        let pixbuf: *mut GdkPixbuf = pixbuf.to_glib_none().0;

        unsafe {
            sys::notify_notification_set_image_from_pixbuf(self.handle,
                                                            pixbuf);
        }
    }

    /// Clears all hints from the notification.
    pub fn clear_hints(&self) {
        unsafe {
            sys::notify_notification_clear_hints(self.handle);
        }
    }
}

/// An error that can happen when attempting to show a notification.
#[derive(Debug)]
pub struct NotificationShowError {
    message: String,
}

impl fmt::Display for NotificationShowError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error showing notification: {}", self.message)
    }
}

impl Error for NotificationShowError {
    fn description(&self) -> &str {
        "notification show error"
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate r2d2;
extern crate r2d2_sqlite;
extern crate rusqlite;

use std::error::Error;
use std::sync::Arc;

use iron::prelude::*;
use iron::{typemap, BeforeMiddleware};
use std::path::{Path};

/// Pool of `SqliteConnectionManager` kept by the Iron middleware
pub type RusqlitePool = Arc<r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>>;

/// Iron rusqlite middleware
pub struct RusqliteMiddleware {
    /// Pool of connections to SQLite through the rusqlite library
    pub pool: RusqlitePool
}

pub struct Value(RusqlitePool);

impl typemap::Key for RusqliteMiddleware { type Value = Value; }

impl RusqliteMiddleware {

    pub fn new<P: AsRef<Path>>(path: P) -> Result<RusqliteMiddleware, Box<Error>> {
        let config = r2d2::Config::default();
        let manager = r2d2_sqlite::SqliteConnectionManager::new(path);
        let pool = r2d2::Pool::new(config, manager)?;

        Ok(RusqliteMiddleware{ pool: Arc::new(pool) })
    }

    pub fn new_with_flags<P: AsRef<Path>>(path: P, flags: rusqlite::OpenFlags) -> Result<RusqliteMiddleware, Box<Error>> {
        let config = r2d2::Config::default();
        let manager = r2d2_sqlite::SqliteConnectionManager::new_with_flags(path, flags);
        let pool = r2d2::Pool::new(config, manager)?;

        Ok(RusqliteMiddleware{ pool: Arc::new(pool) })
    }

    pub fn get_connection(&self) -> r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager> {
        let poll = self.pool.clone();
        poll.get().unwrap()
    }
}

impl BeforeMiddleware for RusqliteMiddleware {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<RusqliteMiddleware>(Value(self.pool.clone()));
        Ok(())
    }
}

pub trait RusqliteRequestExtension {
    fn database_connection(&self) -> r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>;
}

impl<'a, 'b> RusqliteRequestExtension for Request<'a, 'b> {
    fn database_connection(&self) -> r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager> {
        let pv = self.extensions.get::<RusqliteMiddleware>().unwrap();  // Is this safe?
        let &Value(ref poll) = pv;
        poll.get().unwrap()
    }
}
<commit_msg>Documented the library<commit_after>extern crate iron;
extern crate r2d2;
extern crate r2d2_sqlite;
extern crate rusqlite;

use std::error::Error;
use std::sync::Arc;

use iron::prelude::*;
use iron::{typemap, BeforeMiddleware};
use std::path::{Path};

/// Pool of `SqliteConnectionManager` kept by the Iron middleware
pub type RusqlitePool = Arc<r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>>;

/// Iron rusqlite middleware
pub struct RusqliteMiddleware {
    /// Pool of connections to SQLite through the rusqlite library
    pub pool: RusqlitePool
}

pub struct Value(RusqlitePool);

impl typemap::Key for RusqliteMiddleware { type Value = Value; }

impl RusqliteMiddleware {

    /// Creates a new pooled connection to the SQLite database using the default options `rusqlite`.
    /// The `path` should be the path to the SQLite database file on your system.
    ///
    /// See `rusqlite::Connection::open` for mode details.
    pub fn new<P: AsRef<Path>>(path: P) -> Result<RusqliteMiddleware, Box<Error>> {
        let config = r2d2::Config::default();
        let manager = r2d2_sqlite::SqliteConnectionManager::new(path);
        let pool = r2d2::Pool::new(config, manager)?;

        Ok(RusqliteMiddleware{ pool: Arc::new(pool) })
    }

    /// Creates a new pooled connection to the SQLite database using the given rusqlite flags
    /// (i.e. `rusqlite::OpenFlags`). The `path` should be the path to the SQLite database file
    /// on your system.
    ///
    /// See `rusqlite::Connection::open_with_flags` for mode details.
    pub fn new_with_flags<P: AsRef<Path>>(path: P, flags: rusqlite::OpenFlags) -> Result<RusqliteMiddleware, Box<Error>> {
        let config = r2d2::Config::default();
        let manager = r2d2_sqlite::SqliteConnectionManager::new_with_flags(path, flags);
        let pool = r2d2::Pool::new(config, manager)?;

        Ok(RusqliteMiddleware{ pool: Arc::new(pool) })
    }

    /// Get a handle to a pooled connection for the SQLite database. This can be used to execute
    /// some SQL commands prior to launching your Iron webserver. An example would be creating
    /// tables if they do not currently exist in the database.
    pub fn get_connection(&self) -> r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager> {
        let poll = self.pool.clone();
        poll.get().unwrap()
    }
}

/// Implementation of the `iron::BeforeMiddleware` trait to make this actually Iron middleware.
impl BeforeMiddleware for RusqliteMiddleware {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        // Insert the the value into the request extensions
        req.extensions.insert::<RusqliteMiddleware>(Value(self.pool.clone()));
        Ok(())
    }
}

/// Trait which adds a method the `iron::Request` to enable the retrieval of a database connection.
///
/// ### Example
///
/// ```ignore
/// use iron_rusqlite_middleware::RusqliteMiddlewareExtension;
///
/// fn handler(req: &mut Request) -> IronResult<Response> {
///     let conn = req.database_connection();
///
///     // Do stuff with the rusqlite::Connection object
///
///     Ok(Response::with((status::Ok, "Done.")))
/// }
/// ```
pub trait RusqliteRequestExtension {
    /// Returns a pooled connection to the SQLite database. The connection is automatically returned
    /// to the connection pool when the pool connection is dropped.
    ///
    /// **Panics** if the `RusqliteMiddleware` has not been added to the Iron app, or if retrieving
    /// the database connection times out.
    fn database_connection(&self) -> r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>;
}

/// Implementation of the `RusqliteRequestExention` for the `iron::Request`.
impl<'a, 'b> RusqliteRequestExtension for Request<'a, 'b> {
    fn database_connection(&self) -> r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager> {
        let pv = self.extensions.get::<RusqliteMiddleware>().unwrap();  // Is this safe?
        let &Value(ref poll) = pv;
        poll.get().unwrap()
    }
}
<|endoftext|>