<commit_before>use std::fs::File;
use std::path::Path;
use std::sync::Mutex;
use std::time::{Duration, Instant};

use prettytable::{cell, row::Row, Table};

use crate::bvh::BVH;

lazy_static::lazy_static! {
    static ref STATS: Mutex<Statistics> = Mutex::new(Statistics::new());
}

macro_rules! stats {
    () => {
        STATS.lock().unwrap()
    };
}

macro_rules! current_scene {
    () => {
        stats!().current().unwrap()
    };
}

pub fn print_and_save(path: &Path) {
    let table = stats!().table();
    table.printstd();
    let mut stats_file = File::create(path).unwrap();
    table.print(&mut stats_file).unwrap();
}

pub fn new_scene(name: &str) {
    stats!().new_scene(name);
}

pub fn time(name: &str) -> TimerHandle {
    current_scene!().start_timer(name)
}

fn stop_timer(name: &str) {
    current_scene!().stop_timer(name);
}

pub fn start_bvh() {
    let mut handle = time("BVH");
    handle.deactivate();
}

pub fn stop_bvh(bvh: &BVH) {
    stop_timer("BVH");
    current_scene!().analyze_bvh(bvh);
}

pub fn start_render() {
    let mut handle = time("Render");
    handle.deactivate();
}

pub fn stop_render(ray_count: usize) {
    stop_timer("Render");
    current_scene!().ray_count = ray_count;
}

struct Statistics {
    scene_stats: Vec<SceneStatistics>,
}

impl Statistics {
    fn new() -> Statistics {
        Statistics {
            scene_stats: Vec::new(),
        }
    }

    fn new_scene(&mut self, name: &str) {
        self.scene_stats.push(SceneStatistics::new(name));
    }

    fn current(&mut self) -> Option<&mut SceneStatistics> {
        self.scene_stats.iter_mut().last()
    }

    fn table(&self) -> Table {
        let mut names = vec![cell!("")];
        let mut timer_rows = Vec::new();
        let mut mrps = vec![cell!("Mrays/s")];
        let mut n_tris = vec![cell!("Triangles")];
        let mut bvh_size = vec![cell!("BVH nodes")];
        for (timer, l) in &self.scene_stats[0].timers {
            let mut row = Row::empty();
            row.add_cell(cell!(format!("{}{}", "| ".repeat(*l), timer.name)));
            timer_rows.push((&timer.name, row))
        }
        for stats in &self.scene_stats {
            names.push(cell!(stats.scene));
            mrps.push(cell!(stats.mrps()));
            n_tris.push(cell!(stats.n_tris));
            bvh_size.push(cell!(stats.bvh_size));
            for (name, row) in &mut timer_rows {
                let timer = stats.get_timer(name).unwrap();
                row.add_cell(cell!(timer.pretty_duration()));
            }
        }
        let mut table = Table::new();
        table.add_row(Row::new(names));
        table.add_row(Row::new(mrps));
        for (_, row) in timer_rows {
            table.add_row(row);
        }
        table.add_row(Row::new(n_tris));
        table.add_row(Row::new(bvh_size));
        table
    }
}

struct SceneStatistics {
    scene: String,
    timers: Vec<(Timer, usize)>,
    active_timers: Vec<usize>,
    ray_count: usize,
    n_tris: usize,
    bvh_size: usize,
}

impl SceneStatistics {
    fn new(name: &str) -> SceneStatistics {
        SceneStatistics {
            scene: name.to_string(),
            timers: Vec::new(),
            active_timers: Vec::new(),
            ray_count: 0,
            n_tris: 0,
            bvh_size: 0,
        }
    }

    fn start_timer(&mut self, name: &str) -> TimerHandle {
        let timer = Timer::new(name);
        let handle = timer.handle();
        self.timers.push((timer, self.active_timers.len()));
        self.active_timers.push(self.timers.len() - 1);
        handle
    }

    fn stop_timer(&mut self, name: &str) {
        if let Some(i) = self.active_timers.pop() {
            let (timer, _) = &mut self.timers[i];
            if timer.name == name {
                timer.stop();
                return;
            } else {
                panic!("Timer '{}' not on top of timer stack", name);
            }
        } else {
            panic!(
                "Tried to stop timer '{}' when there are no active timers",
                name
            );
        }
    }

    fn analyze_bvh(&mut self, bvh: &BVH) {
        self.n_tris = bvh.n_tris();
        self.bvh_size = bvh.size();
    }

    fn get_timer(&self, name: &str) -> Option<&Timer> {
        for (timer, _) in &self.timers {
            if timer.name == name {
                return Some(timer);
            }
        }
        None
    }

    fn mrps(&self) -> String {
        let render_timer = self.get_timer("Render").unwrap();
        let render_duration = render_timer.duration.unwrap();
        let float_time = render_duration.as_secs() as f64
            + f64::from(render_duration.subsec_nanos()) / 1_000_000_000.0;
        let mrps = self.ray_count as f64 / float_time / 1_000_000.0;
        format!("{:#.2?}", mrps)
    }
}

#[derive(Clone, Debug)]
pub struct Timer {
    name: String,
    start: Instant,
    duration: Option<Duration>,
}

impl Timer {
    fn new(name: &str) -> Timer {
        Timer {
            name: name.to_string(),
            start: Instant::now(),
            duration: None,
        }
    }

    fn stop(&mut self) {
        assert!(
            self.duration.is_none(),
            "Tried to stop already stopped timer!"
        );
        self.duration = Some(self.start.elapsed());
    }

    fn pretty_duration(&self) -> String {
        if let Some(duration) = &self.duration {
            format!("{:#.2?}", duration)
        } else {
            format!("{:#.2?}", self.start.elapsed())
        }
    }

    fn handle(&self) -> TimerHandle {
        TimerHandle {
            name: self.name.clone(),
            active: true,
        }
    }
}

pub struct TimerHandle {
    name: String,
    active: bool,
}

impl TimerHandle {
    pub fn stop(&mut self) {
        stop_timer(&self.name);
        self.deactivate();
    }

    // Prevent handle from stopping the timer when dropped
    fn deactivate(&mut self) {
        self.active = false;
    }
}

impl Drop for TimerHandle {
    fn drop(&mut self) {
        if self.active {
            self.stop()
        }
    }
}
<commit_msg>Add ray count to stats<commit_after>use std::fs::File;
use std::path::Path;
use std::sync::Mutex;
use std::time::{Duration, Instant};

use prettytable::{cell, row::Row, Table};

use crate::bvh::BVH;

lazy_static::lazy_static! {
    static ref STATS: Mutex<Statistics> = Mutex::new(Statistics::new());
}

macro_rules! stats {
    () => {
        STATS.lock().unwrap()
    };
}

macro_rules! current_scene {
    () => {
        stats!().current().unwrap()
    };
}

pub fn print_and_save(path: &Path) {
    let table = stats!().table();
    table.printstd();
    let mut stats_file = File::create(path).unwrap();
    table.print(&mut stats_file).unwrap();
}

pub fn new_scene(name: &str) {
    stats!().new_scene(name);
}

pub fn time(name: &str) -> TimerHandle {
    current_scene!().start_timer(name)
}

fn stop_timer(name: &str) {
    current_scene!().stop_timer(name);
}

pub fn start_bvh() {
    let mut handle = time("BVH");
    handle.deactivate();
}

pub fn stop_bvh(bvh: &BVH) {
    stop_timer("BVH");
    current_scene!().analyze_bvh(bvh);
}

pub fn start_render() {
    let mut handle = time("Render");
    handle.deactivate();
}

pub fn stop_render(ray_count: usize) {
    stop_timer("Render");
    current_scene!().ray_count = ray_count;
}

struct Statistics {
    scene_stats: Vec<SceneStatistics>,
}

impl Statistics {
    fn new() -> Statistics {
        Statistics {
            scene_stats: Vec::new(),
        }
    }

    fn new_scene(&mut self, name: &str) {
        self.scene_stats.push(SceneStatistics::new(name));
    }

    fn current(&mut self) -> Option<&mut SceneStatistics> {
        self.scene_stats.iter_mut().last()
    }

    fn table(&self) -> Table {
        let mut names = vec![cell!("")];
        let mut timer_rows = Vec::new();
        let mut mrps = vec![cell!("Mrays/s")];
        let mut n_tris = vec![cell!("Triangles")];
        let mut bvh_size = vec![cell!("BVH Nodes")];
        let mut n_rays = vec![cell!("Rays")];
        for (timer, l) in &self.scene_stats[0].timers {
            let mut row = Row::empty();
            row.add_cell(cell!(format!("{}{}", "| ".repeat(*l), timer.name)));
            timer_rows.push((&timer.name, row))
        }
        for stats in &self.scene_stats {
            names.push(cell!(stats.scene));
            mrps.push(cell!(stats.mrps()));
            n_tris.push(cell!(stats.n_tris));
            bvh_size.push(cell!(stats.bvh_size));
            n_rays.push(cell!(stats.ray_count));
            for (name, row) in &mut timer_rows {
                let timer = stats.get_timer(name).unwrap();
                row.add_cell(cell!(timer.pretty_duration()));
            }
        }
        let mut table = Table::new();
        table.add_row(Row::new(names));
        table.add_row(Row::new(mrps));
        for (_, row) in timer_rows {
            table.add_row(row);
        }
        table.add_row(Row::new(n_rays));
        table.add_row(Row::new(n_tris));
        table.add_row(Row::new(bvh_size));
        table
    }
}

struct SceneStatistics {
    scene: String,
    timers: Vec<(Timer, usize)>,
    active_timers: Vec<usize>,
    ray_count: usize,
    n_tris: usize,
    bvh_size: usize,
}

impl SceneStatistics {
    fn new(name: &str) -> SceneStatistics {
        SceneStatistics {
            scene: name.to_string(),
            timers: Vec::new(),
            active_timers: Vec::new(),
            ray_count: 0,
            n_tris: 0,
            bvh_size: 0,
        }
    }

    fn start_timer(&mut self, name: &str) -> TimerHandle {
        let timer = Timer::new(name);
        let handle = timer.handle();
        self.timers.push((timer, self.active_timers.len()));
        self.active_timers.push(self.timers.len() - 1);
        handle
    }

    fn stop_timer(&mut self, name: &str) {
        if let Some(i) = self.active_timers.pop() {
            let (timer, _) = &mut self.timers[i];
            if timer.name == name {
                timer.stop();
                return;
            } else {
                panic!("Timer '{}' not on top of timer stack", name);
            }
        } else {
            panic!(
                "Tried to stop timer '{}' when there are no active timers",
                name
            );
        }
    }

    fn analyze_bvh(&mut self, bvh: &BVH) {
        self.n_tris = bvh.n_tris();
        self.bvh_size = bvh.size();
    }

    fn get_timer(&self, name: &str) -> Option<&Timer> {
        for (timer, _) in &self.timers {
            if timer.name == name {
                return Some(timer);
            }
        }
        None
    }

    fn mrps(&self) -> String {
        let render_timer = self.get_timer("Render").unwrap();
        let render_duration = render_timer.duration.unwrap();
        let float_time = render_duration.as_secs() as f64
            + f64::from(render_duration.subsec_nanos()) / 1_000_000_000.0;
        let mrps = self.ray_count as f64 / float_time / 1_000_000.0;
        format!("{:#.2?}", mrps)
    }
}

#[derive(Clone, Debug)]
pub struct Timer {
    name: String,
    start: Instant,
    duration: Option<Duration>,
}

impl Timer {
    fn new(name: &str) -> Timer {
        Timer {
            name: name.to_string(),
            start: Instant::now(),
            duration: None,
        }
    }

    fn stop(&mut self) {
        assert!(
            self.duration.is_none(),
            "Tried to stop already stopped timer!"
        );
        self.duration = Some(self.start.elapsed());
    }

    fn pretty_duration(&self) -> String {
        if let Some(duration) = &self.duration {
            format!("{:#.2?}", duration)
        } else {
            format!("{:#.2?}", self.start.elapsed())
        }
    }

    fn handle(&self) -> TimerHandle {
        TimerHandle {
            name: self.name.clone(),
            active: true,
        }
    }
}

pub struct TimerHandle {
    name: String,
    active: bool,
}

impl TimerHandle {
    pub fn stop(&mut self) {
        stop_timer(&self.name);
        self.deactivate();
    }

    // Prevent handle from stopping the timer when dropped
    fn deactivate(&mut self) {
        self.active = false;
    }
}

impl Drop for TimerHandle {
    fn drop(&mut self) {
        if self.active {
            self.stop()
        }
    }
}
<|endoftext|>


<commit_before>use bindings::*;
use context::Context;
use function::Function;
use util::NativeRef;
use std::str::raw::from_c_str;
/// An ELF binary reader
native_ref!(ReadElf, _reader, jit_readelf_t)
impl ReadElf {
	/// Open a new ELF binary
	pub fn new(filename:&str) -> ReadElf {
		unsafe {
			let mut this = RawPtr::null();
			let code = filename.with_c_str(|c_name| unsafe {
				jit_readelf_open(&mut this, c_name, 0)
			});
			if this.is_null() {
				fail!("'{}' couldn't be opened due to {}", filename, code);
			} else {
				NativeRef::from_ptr(this)
			}
		}
	}
	#[inline]
	/// Get the name of this ELF binary
	pub fn get_name(&self) -> String {
		unsafe {
			from_c_str(jit_readelf_get_name(self.as_ptr()))
		}
	}
	#[inline]
	pub fn add_to_context(&self, ctx:&Context) {
		unsafe {
			jit_readelf_add_to_context(self.as_ptr(), ctx.as_ptr())
		}
	}
	#[inline]
	/// Get a simple in the ELF binary
	pub unsafe fn get_symbol<T>(&self, symbol:&str) -> *T {
		symbol.with_c_str(|c_symbol| unsafe {
			jit_readelf_get_symbol(self.as_ptr(), c_symbol) as *T
		})
	}
}
impl Drop for ReadElf {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_readelf_close(self.as_ptr())
		}
	}
}

/// An ELF binary reader
native_ref!(WriteElf, _writer, jit_writeelf_t)
impl WriteElf {
	#[inline]
	/// Create a new ELF binary reader
	pub fn new(lib_name:&str) -> WriteElf {
		lib_name.with_c_str(|c_lib_name| unsafe {
			NativeRef::from_ptr(jit_writeelf_create(c_lib_name))
		})
	}
	#[inline]
	/// Write to the filename given (not implemented by LibJIT yet)
	pub fn write(&self, filename:&str) -> bool {
		filename.with_c_str(|c_filename| unsafe {
			jit_writeelf_write(self.as_ptr(), c_filename) != 0
		})
	}
	#[inline]
	/// Add a function to the ELF
	pub fn add_function(&self, func:&Function, name:&str) -> bool {
		name.with_c_str(|c_name| unsafe {
			jit_writeelf_add_function(self.as_ptr(), func.as_ptr(), c_name) != 0
		})
	}
	#[inline]
	/// Add a dependency to the ELF
	pub fn add_needed(&self, lib_name:&str) -> bool {
		lib_name.with_c_str(|c_lib_name| unsafe {
			jit_writeelf_add_needed(self.as_ptr(), c_lib_name) != 0
		})
	}
}
impl Drop for WriteElf {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_writeelf_destroy(self.as_ptr())
		}
	}
}
#[test]
fn test_elf() {
	let elf = ReadElf::new("/usr/lib/libjit.so.0");
	assert_eq!(elf.get_name().as_slice(), "libjit.so.0");
}<commit_msg>Remove unnecessary unsafe blocks<commit_after>use bindings::*;
use context::Context;
use function::Function;
use util::NativeRef;
use std::str::raw::from_c_str;
/// An ELF binary reader
native_ref!(ReadElf, _reader, jit_readelf_t)
impl ReadElf {
	/// Open a new ELF binary
	pub fn new(filename:&str) -> ReadElf {
		unsafe {
			let mut this = RawPtr::null();
			let code = filename.with_c_str(|c_name|
				jit_readelf_open(&mut this, c_name, 0)
			);
			if this.is_null() {
				fail!("'{}' couldn't be opened due to {}", filename, code);
			} else {
				NativeRef::from_ptr(this)
			}
		}
	}
	#[inline]
	/// Get the name of this ELF binary
	pub fn get_name(&self) -> String {
		unsafe {
			from_c_str(jit_readelf_get_name(self.as_ptr()))
		}
	}
	#[inline]
	pub fn add_to_context(&self, ctx:&Context) {
		unsafe {
			jit_readelf_add_to_context(self.as_ptr(), ctx.as_ptr())
		}
	}
	#[inline]
	/// Get a simple in the ELF binary
	pub unsafe fn get_symbol<T>(&self, symbol:&str) -> *T {
		symbol.with_c_str(|c_symbol|
			jit_readelf_get_symbol(self.as_ptr(), c_symbol) as *T
		)
	}
}
impl Drop for ReadElf {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_readelf_close(self.as_ptr())
		}
	}
}

/// An ELF binary reader
native_ref!(WriteElf, _writer, jit_writeelf_t)
impl WriteElf {
	#[inline]
	/// Create a new ELF binary reader
	pub fn new(lib_name:&str) -> WriteElf {
		lib_name.with_c_str(|c_lib_name| unsafe {
			NativeRef::from_ptr(jit_writeelf_create(c_lib_name))
		})
	}
	#[inline]
	/// Write to the filename given (not implemented by LibJIT yet)
	pub fn write(&self, filename:&str) -> bool {
		filename.with_c_str(|c_filename| unsafe {
			jit_writeelf_write(self.as_ptr(), c_filename) != 0
		})
	}
	#[inline]
	/// Add a function to the ELF
	pub fn add_function(&self, func:&Function, name:&str) -> bool {
		name.with_c_str(|c_name| unsafe {
			jit_writeelf_add_function(self.as_ptr(), func.as_ptr(), c_name) != 0
		})
	}
	#[inline]
	/// Add a dependency to the ELF
	pub fn add_needed(&self, lib_name:&str) -> bool {
		lib_name.with_c_str(|c_lib_name| unsafe {
			jit_writeelf_add_needed(self.as_ptr(), c_lib_name) != 0
		})
	}
}
impl Drop for WriteElf {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_writeelf_destroy(self.as_ptr())
		}
	}
}
#[test]
fn test_elf() {
	let elf = ReadElf::new("/usr/lib/libjit.so.0");
	assert_eq!(elf.get_name().as_slice(), "libjit.so.0");
}<|endoftext|>


<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::string::String;
use syntax::ast;
use syntax::ast::{Ident};
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, MacItem, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse;
use syntax::parse::{token, ParseSess};
use syntax::parse::token::Token;
use syntax::parse::parser::Parser;
use rustc::plugin::Registry;

struct Peg{
  name: Ident,
  rules: Vec<Rule>
}

struct Rule{
  name: Ident,
  def: Box<Expression>
}

enum Expression{
  LiteralStrExpr(String), // "match me"
  AnySingleCharExpr, // .
  NonTerminalSymbol(Ident), // another_rule
  SequenceExpr(Vec<Box<Expression>>)
}

struct ParseError{
  span: codemap::Span,
  msg: String
}

struct PegParser<'a>
{
  rp: Parser<'a> // rust parser
}

impl<'a> PegParser<'a>
{
  fn new(sess: &'a ParseSess,
         cfg: ast::CrateConfig,
         tts: Vec<ast::TokenTree>) -> PegParser<'a>
  {
    PegParser{rp: parse::new_parser_from_tts(sess, cfg, tts)}
  }

  fn parse_grammar(&mut self) -> Peg
  {
    let grammar_name = self.parse_grammar_decl();
    let rules = self.parse_rules();
    Peg{name: grammar_name, rules: rules}
  }

  fn parse_grammar_decl(&mut self) -> Ident
  {
    if !self.eat_grammar_keyword() {
      let token_str = self.rp.this_token_to_str();
      self.rp.fatal(
        format!("expected the grammar declaration (of the form: `grammar <grammar-name>;`), found instead `{}`",
          token_str).as_slice())
    }
    let grammar_name = self.rp.parse_ident();
    self.rp.expect(&token::SEMI);
    grammar_name
  }

  fn eat_grammar_keyword(&mut self) -> bool
  {
    let is_grammar_kw = match self.rp.token {
      token::IDENT(sid, false) => "grammar" == id_to_string(sid).as_slice(),
      _ => false
    };
    if is_grammar_kw { self.rp.bump() }
    is_grammar_kw
  }

  fn parse_rules(&mut self) -> Vec<Rule>
  {
    let mut rules = vec![];
    while(self.rp.token != token::EOF)
    {
      rules.push(self.parse_rule());
    }
    rules
  }

  fn parse_rule(&mut self) -> Rule
  {
    let name = self.parse_rule_decl();
    self.rp.expect(&token::EQ);
    let body = self.parse_rule_rhs(id_to_string(name).as_slice());
    Rule{name: name, def: body}
  }

  fn parse_rule_decl(&mut self) -> Ident
  {
    self.rp.parse_ident()
  }

  fn parse_rule_rhs(&mut self, rule_name: &str) -> Box<Expression>
  {
    self.parse_rule_seq(rule_name)
  }

  fn parse_rule_seq(&mut self, rule_name: &str) -> Box<Expression>
  {
    let mut seq = Vec::new();
    loop{
      match self.parse_rule_atom(rule_name){
        Some(expr) => seq.push(expr),
        None => break
      }
    }
    if seq.len() == 0 {
      self.rp.fatal(format!("The rule {} must have a definition body.", rule_name).as_slice());
    }
    box SequenceExpr(seq)
  }

  fn parse_rule_atom(&mut self, rule_name: &str) -> Option<Box<Expression>>
  {
    let token = self.rp.token.clone();
    match token {
      token::LIT_STR(id) => {
        self.rp.bump();
        Some(box LiteralStrExpr(id_to_string(id)))
      },
      token::DOT => {
        self.rp.bump();
        Some(box AnySingleCharExpr)
      },
      token::LPAREN => {
        self.rp.bump();
        let res = self.parse_rule_rhs(rule_name);
        self.rp.expect(&token::RPAREN);
        Some(res)
      },
      token::IDENT(id, _) => {
        if(self.is_rule_decl()) { None }
        else {
          self.rp.bump();
          Some(box NonTerminalSymbol(id))
        }
      },
      token::EOF => { None },
      _ => { self.rp.unexpected_last(&token); }
    }
  }

  fn is_rule_decl(&mut self) -> bool
  {
    self.rp.look_ahead(1, |t| match t { &token::EQ => true, _ => false})
  }
}

fn id_to_string(id: Ident) -> String
{
  String::from_str(token::get_ident(id).get())
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
  reg.register_macro("peg", expand)
}

fn expand(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<MacResult> {
  parse(cx, tts)
}

fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Box<MacResult> {
  use syntax::print::pprust;

  let mut parser = PegParser::new(cx.parse_sess(), cx.cfg(), Vec::from_slice(tts));
  let peg = parser.parse_grammar();

  compile_peg(cx, &peg)
}

struct ToTokensVec<T>
{
  v: Vec<T>
}

impl<T: ToTokens> ToTokens for ToTokensVec<T>
{
  fn to_tokens(&self, cx: &ExtCtxt) -> Vec<ast::TokenTree> {
    let mut tts = Vec::new();
    for e in self.v.iter() {
      tts = tts.append(e.to_tokens(cx).as_slice());
    }
    tts
  }
}

fn compile_peg(cx: &ExtCtxt, peg: &Peg) -> Box<MacResult>
{
  let grammar_name = peg.name;

  let parse_fn = compile_entry_point(cx, &peg.rules.as_slice()[0].name);

  let mut rule_items = Vec::new();

  for rule in peg.rules.iter()
  {
    let rule_name = rule.name;
    let rule_def = compile_rule_def(cx, &rule.def);
    rule_items.push(quote_item!(cx,
      fn $rule_name (input: &str, pos: uint) -> Result<uint, String>
      {
        $rule_def
      }
    ).unwrap())
  }

  let items = ToTokensVec{v: rule_items};

  MacItem::new(quote_item!(cx,
    pub mod $grammar_name
    {
      $parse_fn
      $items
    }
  ).unwrap())
}

fn compile_entry_point(cx: &ExtCtxt, start_rule: &Ident) -> ast::P<ast::Item>
{
  (quote_item!(cx,
    pub fn parse<'a>(input: &'a str) -> Result<Option<&'a str>, String>
    {
      match $start_rule(input, 0) {
        Ok(pos) => {
          assert!(pos <= input.len())
          if pos == input.len() {
            Ok(None)
          } else {
            Ok(Some(input.slice_from(pos)))
          }
        },
        Err(msg) => Err(msg)
      }
    })).unwrap()
}

fn compile_rule_def(cx: &ExtCtxt, expr: &Box<Expression>) -> ast::P<ast::Expr>
{
  match expr {
    & box LiteralStrExpr(ref lit_str) => {
      let s_len = lit_str.len();
      let lit_str_slice = lit_str.as_slice();
      quote_expr!(cx,
        if input.len() - pos == 0 {
          Err(format!("End of input when matching the literal `{}`", $lit_str_slice))
        } else if input.slice_from(pos).starts_with($lit_str_slice) {
          Ok(pos + $s_len)
        } else {
          Err(format!("Expected {} but got `{}`", $lit_str_slice, input.slice_from(pos)))
        }
      )
    },
    & box AnySingleCharExpr => {
      quote_expr!(cx,
        if input.len() - pos > 0 {
          Ok(pos + 1)
        } else {
          Err(format!("End of input when matching `.`"))
        }
      )
    },
    & box NonTerminalSymbol(ref id) => {
      quote_expr!(cx,
        $id(input, pos)
      )
    },
    & box SequenceExpr(ref seq) => {
      compile_sequence(cx, seq.as_slice())
    }
  }
}

fn compile_sequence<'a>(cx: &ExtCtxt, seq: &'a [Box<Expression>]) -> ast::P<ast::Expr>
{
  assert!(seq.len() > 0);
  let head = compile_rule_def(cx, seq.head().unwrap());
  if seq.len() == 1 {
    head
  } else {
    let tail = compile_sequence(cx, seq.tail());
    quote_expr!(cx,
      match $head {
        Ok(pos) => {
          $tail
        }
        x => x
      }
    )
  }
}

<commit_msg>[Refactoring] Split into several functions the compilation.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::string::String;
use syntax::ast;
use syntax::ast::{Ident};
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, MacItem, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse;
use syntax::parse::{token, ParseSess};
use syntax::parse::token::Token;
use syntax::parse::parser::Parser;
use rustc::plugin::Registry;

struct Peg{
  name: Ident,
  rules: Vec<Rule>
}

struct Rule{
  name: Ident,
  def: Box<Expression>
}

enum Expression{
  StrLiteral(String), // "match me"
  AnySingleChar, // .
  NonTerminalSymbol(Ident), // another_rule
  Sequence(Vec<Box<Expression>>)
}

struct ParseError{
  span: codemap::Span,
  msg: String
}

struct PegParser<'a>
{
  rp: Parser<'a> // rust parser
}

impl<'a> PegParser<'a>
{
  fn new(sess: &'a ParseSess,
         cfg: ast::CrateConfig,
         tts: Vec<ast::TokenTree>) -> PegParser<'a>
  {
    PegParser{rp: parse::new_parser_from_tts(sess, cfg, tts)}
  }

  fn parse_grammar(&mut self) -> Peg
  {
    let grammar_name = self.parse_grammar_decl();
    let rules = self.parse_rules();
    Peg{name: grammar_name, rules: rules}
  }

  fn parse_grammar_decl(&mut self) -> Ident
  {
    if !self.eat_grammar_keyword() {
      let token_str = self.rp.this_token_to_str();
      self.rp.fatal(
        format!("expected the grammar declaration (of the form: `grammar <grammar-name>;`), found instead `{}`",
          token_str).as_slice())
    }
    let grammar_name = self.rp.parse_ident();
    self.rp.expect(&token::SEMI);
    grammar_name
  }

  fn eat_grammar_keyword(&mut self) -> bool
  {
    let is_grammar_kw = match self.rp.token {
      token::IDENT(sid, false) => "grammar" == id_to_string(sid).as_slice(),
      _ => false
    };
    if is_grammar_kw { self.rp.bump() }
    is_grammar_kw
  }

  fn parse_rules(&mut self) -> Vec<Rule>
  {
    let mut rules = vec![];
    while(self.rp.token != token::EOF)
    {
      rules.push(self.parse_rule());
    }
    rules
  }

  fn parse_rule(&mut self) -> Rule
  {
    let name = self.parse_rule_decl();
    self.rp.expect(&token::EQ);
    let body = self.parse_rule_rhs(id_to_string(name).as_slice());
    Rule{name: name, def: body}
  }

  fn parse_rule_decl(&mut self) -> Ident
  {
    self.rp.parse_ident()
  }

  fn parse_rule_rhs(&mut self, rule_name: &str) -> Box<Expression>
  {
    self.parse_rule_seq(rule_name)
  }

  fn parse_rule_seq(&mut self, rule_name: &str) -> Box<Expression>
  {
    let mut seq = Vec::new();
    loop{
      match self.parse_rule_atom(rule_name){
        Some(expr) => seq.push(expr),
        None => break
      }
    }
    if seq.len() == 0 {
      self.rp.fatal(format!("The rule {} must have a definition body.", rule_name).as_slice());
    }
    box Sequence(seq)
  }

  fn parse_rule_atom(&mut self, rule_name: &str) -> Option<Box<Expression>>
  {
    let token = self.rp.token.clone();
    match token {
      token::LIT_STR(id) => {
        self.rp.bump();
        Some(box StrLiteral(id_to_string(id)))
      },
      token::DOT => {
        self.rp.bump();
        Some(box AnySingleChar)
      },
      token::LPAREN => {
        self.rp.bump();
        let res = self.parse_rule_rhs(rule_name);
        self.rp.expect(&token::RPAREN);
        Some(res)
      },
      token::IDENT(id, _) => {
        if(self.is_rule_decl()) { None }
        else {
          self.rp.bump();
          Some(box NonTerminalSymbol(id))
        }
      },
      token::EOF => { None },
      _ => { self.rp.unexpected_last(&token); }
    }
  }

  fn is_rule_decl(&mut self) -> bool
  {
    self.rp.look_ahead(1, |t| match t { &token::EQ => true, _ => false})
  }
}

fn id_to_string(id: Ident) -> String
{
  String::from_str(token::get_ident(id).get())
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
  reg.register_macro("peg", expand)
}

fn expand(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<MacResult> {
  parse(cx, tts)
}

fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Box<MacResult> {
  use syntax::print::pprust;

  let mut parser = PegParser::new(cx.parse_sess(), cx.cfg(), Vec::from_slice(tts));
  let peg = parser.parse_grammar();

  compile_peg(cx, &peg)
}

struct ToTokensVec<T>
{
  v: Vec<T>
}

impl<T: ToTokens> ToTokens for ToTokensVec<T>
{
  fn to_tokens(&self, cx: &ExtCtxt) -> Vec<ast::TokenTree> {
    let mut tts = Vec::new();
    for e in self.v.iter() {
      tts = tts.append(e.to_tokens(cx).as_slice());
    }
    tts
  }
}

fn compile_peg(cx: &ExtCtxt, peg: &Peg) -> Box<MacResult>
{
  let grammar_name = peg.name;

  let parse_fn = compile_entry_point(cx, &peg.rules.as_slice()[0].name);

  let mut rule_items = Vec::new();

  for rule in peg.rules.iter()
  {
    let rule_name = rule.name;
    let rule_def = compile_rule_rhs(cx, &rule.def);
    rule_items.push(quote_item!(cx,
      fn $rule_name (input: &str, pos: uint) -> Result<uint, String>
      {
        $rule_def
      }
    ).unwrap())
  }

  let items = ToTokensVec{v: rule_items};

  MacItem::new(quote_item!(cx,
    pub mod $grammar_name
    {
      $parse_fn
      $items
    }
  ).unwrap())
}

fn compile_entry_point(cx: &ExtCtxt, start_rule: &Ident) -> ast::P<ast::Item>
{
  (quote_item!(cx,
    pub fn parse<'a>(input: &'a str) -> Result<Option<&'a str>, String>
    {
      match $start_rule(input, 0) {
        Ok(pos) => {
          assert!(pos <= input.len())
          if pos == input.len() {
            Ok(None)
          } else {
            Ok(Some(input.slice_from(pos)))
          }
        },
        Err(msg) => Err(msg)
      }
    })).unwrap()
}

fn compile_rule_rhs(cx: &ExtCtxt, expr: &Box<Expression>) -> ast::P<ast::Expr>
{
  match expr {
    & box StrLiteral(ref lit_str) => {
      compile_str_literal(cx, lit_str)
    },
    & box AnySingleChar => {
      compile_any_single_char(cx)
    },
    & box NonTerminalSymbol(ref id) => {
      compile_non_terminal_symbol(cx, id)
    },
    & box Sequence(ref seq) => {
      compile_sequence(cx, seq.as_slice())
    }
  }
}

fn compile_non_terminal_symbol(cx: &ExtCtxt, id: &Ident) -> ast::P<ast::Expr>
{
  quote_expr!(cx,
    $id(input, pos)
  )
}

fn compile_any_single_char(cx: &ExtCtxt) -> ast::P<ast::Expr>
{
  quote_expr!(cx,
    if input.len() - pos > 0 {
      Ok(pos + 1)
    } else {
      Err(format!("End of input when matching `.`"))
    }
  )
}

fn compile_str_literal(cx: &ExtCtxt, lit_str: &String) -> ast::P<ast::Expr>
{
  let s_len = lit_str.len();
  let lit_str_slice = lit_str.as_slice();
  quote_expr!(cx,
    if input.len() - pos == 0 {
      Err(format!("End of input when matching the literal `{}`", $lit_str_slice))
    } else if input.slice_from(pos).starts_with($lit_str_slice) {
      Ok(pos + $s_len)
    } else {
      Err(format!("Expected {} but got `{}`", $lit_str_slice, input.slice_from(pos)))
    }
  )
}

fn compile_sequence<'a>(cx: &ExtCtxt, seq: &'a [Box<Expression>]) -> ast::P<ast::Expr>
{
  assert!(seq.len() > 0);
  let head = compile_rule_rhs(cx, seq.head().unwrap());
  if seq.len() == 1 {
    head
  } else {
    let tail = compile_sequence(cx, seq.tail());
    quote_expr!(cx,
      match $head {
        Ok(pos) => {
          $tail
        }
        x => x
      }
    )
  }
}

<|endoftext|>


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

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OSRng;

#[cfg(unix)]
mod imp {
    use Rng;
    use reader::ReaderRng;
    use std::io::File;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    #[cfg(unix)]
    pub struct OSRng {
        priv inner: ReaderRng<File>
    }

    impl OSRng {
        /// Create a new `OSRng`.
        pub fn new() -> OSRng {
            let reader = File::open(&Path::new("/dev/urandom"));
            let reader = reader.ok().expect("Error opening /dev/urandom");
            let reader_rng = ReaderRng::new(reader);

            OSRng { inner: reader_rng }
        }
    }

    impl Rng for OSRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(windows)]
mod imp {
    use Rng;
    use std::cast;
    use std::libc::{c_ulong, DWORD, BYTE, LPCSTR, BOOL};
    use std::os;

    type HCRYPTPROV = c_ulong;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OSRng {
        priv hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OSRng {
        /// Create a new `OSRng`.
        pub fn new() -> OSRng {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };
            if ret == 0 {
                fail!("couldn't create context: {}", os::last_os_error());
            }
            OSRng { hcryptprov: hcp }
        }
    }

    impl Rng for OSRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { cast::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { cast::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OSRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::OSRng;
    use Rng;
    use std::task;

    #[test]
    fn test_os_rng() {
        let mut r = OSRng::new();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = ~[];
        for _ in range(0, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OSRng::new();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>rand: Fix a bug acquiring a context on windows<commit_after>// Copyright 2013 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.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OSRng;

#[cfg(unix)]
mod imp {
    use Rng;
    use reader::ReaderRng;
    use std::io::File;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    #[cfg(unix)]
    pub struct OSRng {
        priv inner: ReaderRng<File>
    }

    impl OSRng {
        /// Create a new `OSRng`.
        pub fn new() -> OSRng {
            let reader = File::open(&Path::new("/dev/urandom"));
            let reader = reader.ok().expect("Error opening /dev/urandom");
            let reader_rng = ReaderRng::new(reader);

            OSRng { inner: reader_rng }
        }
    }

    impl Rng for OSRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(windows)]
mod imp {
    use Rng;
    use std::cast;
    use std::libc::{c_ulong, DWORD, BYTE, LPCSTR, BOOL};
    use std::os;
    use std::rt::stack;

    type HCRYPTPROV = c_ulong;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OSRng {
        priv hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
    static NTE_BAD_SIGNATURE: DWORD = 0x80090006;

    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OSRng {
        /// Create a new `OSRng`.
        pub fn new() -> OSRng {
            let mut hcp = 0;
            let mut ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            // It turns out that if we can't acquire a context with the
            // NTE_BAD_SIGNATURE error code, the documentation states:
            //
            //     The provider DLL signature could not be verified. Either the
            //     DLL or the digital signature has been tampered with.
            //
            // Sounds fishy, no? As it turns out, our signature can be bad
            // because our Thread Information Block (TIB) isn't exactly what it
            // expects. As to why, I have no idea. The only data we store in the
            // TIB is the stack limit for each thread, but apparently that's
            // enough to make the signature valid.
            //
            // Furthermore, this error only happens the *first* time we call
            // CryptAcquireContext, so we don't have to worry about future
            // calls.
            //
            // Anyway, the fix employed here is that if we see this error, we
            // pray that we're not close to the end of the stack, temporarily
            // set the stack limit to 0 (what the TIB originally was), acquire a
            // context, and then reset the stack limit.
            //
            // Again, I'm not sure why this is the fix, nor why we're getting
            // this error. All I can say is that this seems to allow libnative
            // to progress where it otherwise would be hindered. Who knew?
            if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
                unsafe {
                    let limit = stack::get_sp_limit();
                    stack::record_sp_limit(0);
                    ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                               PROV_RSA_FULL,
                                               CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
                    stack::record_sp_limit(limit);
                }
            }

            if ret == 0 {
                fail!("couldn't create context: {}", os::last_os_error());
            }
            OSRng { hcryptprov: hcp }
        }
    }

    impl Rng for OSRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { cast::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { cast::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OSRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::OSRng;
    use Rng;
    use std::task;

    #[test]
    fn test_os_rng() {
        let mut r = OSRng::new();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = ~[];
        for _ in range(0, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OSRng::new();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::slice::{Items, MutItems};
use std::vec::{Vec, MoveItems};

pub struct Table<T> {
    dimensions: (uint, uint),
    data: Vec<T>
}

impl<T: Clone> Table<T> {
    pub fn from_elem(dimensions: (uint, uint), value: T) -> Table<T> {
        let (width, height) = dimensions;

        Table {
            dimensions: dimensions,
            data: Vec::from_elem(width * height, value)
        }
    }
}

impl<T> Table<T> {
    #[inline]
    fn get_vec_index(&self, index: (uint, uint)) -> uint {
        let (row, column) = index;
        let (width, height) = self.dimensions;

        if row >= height {
            panic!("Table::get_index: `row` overflow ({} >= {})", row, height)
        }
        if column >= width {
            panic!("Table::get_index: `column` overflow ({} >= {})", column, width)
        }

        row * width + column
    }

    pub fn get_dimensions(&self) -> (uint, uint) {
        self.dimensions
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> TableItems<Items<'a, T>> {
        self.data.iter().as_table(self.dimensions)
    }

    #[inline]
    pub fn iter_mut<'a>(&'a mut self) -> TableItems<MutItems<'a, T>> {
        self.data.iter_mut().as_table(self.dimensions)
    }

    #[inline]
    pub fn into_iter<'a>(self) -> TableItems<MoveItems<T>> {
        self.data.into_iter().as_table(self.dimensions)
    }
}

impl<T> Index<(uint, uint), T> for Table<T> {
    #[inline]
    fn index<'a>(&'a self, index: &(uint, uint)) -> &'a T {
        let vec_index = self.get_vec_index(*index);
        self.data.index(&vec_index)
    }
}

impl<T> IndexMut<(uint, uint), T> for Table<T> {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: &(uint, uint)) -> &'a mut T {
        let vec_index = self.get_vec_index(*index);
        self.data.index_mut(&vec_index)
    }
}

pub struct TableItems<T> {
    iter: T,
    dimensions: (uint, uint)
}

impl<A, T: Iterator<A>> Iterator<A> for TableItems<T> {
    #[inline]
    fn next(&mut self) -> Option<A> {
        self.iter.next()
    }
}

pub trait AsTable<'a, T> {
    fn as_table(self, dimensions: (uint, uint)) -> TableItems<Self> {
        TableItems {
            iter: self,
            dimensions: dimensions
        }
    }
}

impl<'a, A, T: Iterator<A>> AsTable<'a, T> for T {}

pub struct TableEnumerate<T> {
    iter: T,
    row_count: uint,
    column_count: uint
}

impl<A, T: Iterator<A>> Iterator<((uint, uint), A)> for TableEnumerate<TableItems<T>> {
    #[inline]
    fn next(&mut self) -> Option<((uint, uint), A)> {
        let (width, _) = self.iter.dimensions;

        match self.iter.next() {
            Some(value) => {
                let ret = Some(((self.row_count, self.column_count), value));

                self.column_count += 1;
                if self.column_count == width {
                    self.row_count += 1;
                    self.column_count = 0;
                }
                ret
            },
            None => None
        }
    }

    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        self.iter.size_hint()
    }
}

impl<T> TableItems<T> {
    pub fn enumerate_2d(self) -> TableEnumerate<TableItems<T>> {
        TableEnumerate {
            iter: self,
            row_count: 0,
            column_count: 0
        }
    }

    pub fn enumerate_2d_from(self, start: (uint, uint)) -> TableEnumerate<TableItems<T>> {
        let (row_start, column_start) = start;

        TableEnumerate {
            iter: self,
            row_count: row_start,
            column_count: column_start
        }
    }

    pub fn enumerate_2d_from_index(self, index: uint) -> TableEnumerate<TableItems<T>> {
        let (width, _) = self.dimensions;
        let row_start = index / width;
        let column_start = index % width;

        TableEnumerate {
            iter: self,
            row_count: row_start,
            column_count: column_start
        }
    }
}
<commit_msg>Adds `inline` to `Table` methods.<commit_after>#![allow(dead_code)]

use std::slice::{Items, MutItems};
use std::vec::{Vec, MoveItems};

pub struct Table<T> {
    dimensions: (uint, uint),
    data: Vec<T>
}

impl<T: Clone> Table<T> {
    #[inline]
    pub fn from_elem(dimensions: (uint, uint), value: T) -> Table<T> {
        let (width, height) = dimensions;

        Table {
            dimensions: dimensions,
            data: Vec::from_elem(width * height, value)
        }
    }
}

impl<T> Table<T> {
    #[inline]
    fn get_vec_index(&self, index: (uint, uint)) -> uint {
        let (row, column) = index;
        let (width, height) = self.dimensions;

        if row >= height {
            panic!("Table::get_index: `row` overflow ({} >= {})", row, height)
        }
        if column >= width {
            panic!("Table::get_index: `column` overflow ({} >= {})", column, width)
        }

        row * width + column
    }

    #[inline]
    pub fn get_dimensions(&self) -> (uint, uint) {
        self.dimensions
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> TableItems<Items<'a, T>> {
        self.data.iter().as_table(self.dimensions)
    }

    #[inline]
    pub fn iter_mut<'a>(&'a mut self) -> TableItems<MutItems<'a, T>> {
        self.data.iter_mut().as_table(self.dimensions)
    }

    #[inline]
    pub fn into_iter<'a>(self) -> TableItems<MoveItems<T>> {
        self.data.into_iter().as_table(self.dimensions)
    }
}

impl<T> Index<(uint, uint), T> for Table<T> {
    #[inline]
    fn index<'a>(&'a self, index: &(uint, uint)) -> &'a T {
        let vec_index = self.get_vec_index(*index);
        self.data.index(&vec_index)
    }
}

impl<T> IndexMut<(uint, uint), T> for Table<T> {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: &(uint, uint)) -> &'a mut T {
        let vec_index = self.get_vec_index(*index);
        self.data.index_mut(&vec_index)
    }
}

pub struct TableItems<T> {
    iter: T,
    dimensions: (uint, uint)
}

impl<A, T: Iterator<A>> Iterator<A> for TableItems<T> {
    #[inline]
    fn next(&mut self) -> Option<A> {
        self.iter.next()
    }
}

pub trait AsTable<'a, T> {
    #[inline]
    fn as_table(self, dimensions: (uint, uint)) -> TableItems<Self> {
        TableItems {
            iter: self,
            dimensions: dimensions
        }
    }
}

impl<'a, A, T: Iterator<A>> AsTable<'a, T> for T {}

pub struct TableEnumerate<T> {
    iter: T,
    row_count: uint,
    column_count: uint
}

impl<A, T: Iterator<A>> Iterator<((uint, uint), A)> for TableEnumerate<TableItems<T>> {
    #[inline]
    fn next(&mut self) -> Option<((uint, uint), A)> {
        let (width, _) = self.iter.dimensions;

        match self.iter.next() {
            Some(value) => {
                let ret = Some(((self.row_count, self.column_count), value));

                self.column_count += 1;
                if self.column_count == width {
                    self.row_count += 1;
                    self.column_count = 0;
                }
                ret
            },
            None => None
        }
    }

    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        self.iter.size_hint()
    }
}

impl<T> TableItems<T> {
    #[inline]
    pub fn enumerate_2d(self) -> TableEnumerate<TableItems<T>> {
        TableEnumerate {
            iter: self,
            row_count: 0,
            column_count: 0
        }
    }

    #[inline]
    pub fn enumerate_2d_from(self, start: (uint, uint)) -> TableEnumerate<TableItems<T>> {
        let (row_start, column_start) = start;

        TableEnumerate {
            iter: self,
            row_count: row_start,
            column_count: column_start
        }
    }

    #[inline]
    pub fn enumerate_2d_from_index(self, index: uint) -> TableEnumerate<TableItems<T>> {
        let (width, _) = self.dimensions;
        let row_start = index / width;
        let column_start = index % width;

        TableEnumerate {
            iter: self,
            row_count: row_start,
            column_count: column_start
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use libc::*;
use std::{ptr, slice, usize};
use std::io::Cursor;
use miniz_oxide::inflate::TINFLStatus;
pub use miniz_oxide::inflate::core::{decompress, inflate_flags};
pub use miniz_oxide::inflate::core::DecompressorOxide as tinfl_decompressor;

pub const TINFL_DECOMPRESS_MEM_TO_MEM_FAILED: size_t = usize::MAX;

unmangle!(
pub unsafe extern "C" fn tinfl_decompress(
    r: *mut tinfl_decompressor,
    in_buf: *const u8,
    in_buf_size: *mut usize,
    out_buf_start: *mut u8,
    out_buf_next: *mut u8,
    out_buf_size: *mut usize,
    flags: u32,
) -> i32 {
    let next_pos = out_buf_next as usize - out_buf_start as usize;
    let out_size = *out_buf_size + next_pos;
    let mut out_cursor = Cursor::new(slice::from_raw_parts_mut(out_buf_start, out_size));
    out_cursor.set_position(next_pos as u64);
    let (status, in_consumed, out_consumed) = decompress(
        r.as_mut().expect("bad decompressor pointer"),
        slice::from_raw_parts(in_buf, *in_buf_size),
        &mut out_cursor,
        flags,
    );

    *in_buf_size = in_consumed;
    *out_buf_size = out_consumed;
    status as i32
}

pub unsafe extern "C" fn tinfl_decompress_mem_to_mem(
    p_out_buf: *mut c_void,
    out_buf_len: size_t,
    p_src_buf: *const c_void,
    src_buf_len: size_t,
    flags: c_int,
) -> size_t {
    let flags = flags as u32;
    let mut decomp = tinfl_decompressor::with_init_state_only();

    let (status, _, out_consumed) =
        decompress(
            &mut decomp,
            slice::from_raw_parts(p_src_buf as *const u8, src_buf_len),
            &mut Cursor::new(slice::from_raw_parts_mut(p_out_buf as *mut u8, out_buf_len)),
            (flags & !inflate_flags::TINFL_FLAG_HAS_MORE_INPUT) | inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF,
        );

    if status != TINFLStatus::Done {
        TINFL_DECOMPRESS_MEM_TO_MEM_FAILED as size_t
    } else {
        out_consumed
    }
}

/// Decompress data from `p_src_buf` to a continuously growing heap-allocated buffer.
///
/// Sets `p_out_len` to the length of the returned buffer.
/// Returns `ptr::null()` if decompression or allocation fails.
/// The buffer should be freed with `miniz_def_free_func`.
pub unsafe extern "C" fn tinfl_decompress_mem_to_heap(
    p_src_buf: *const c_void,
    src_buf_len: size_t,
    p_out_len: *mut size_t,
    flags: c_int,
) -> *mut c_void {
    let flags = flags as u32;
    const MIN_BUFFER_CAPACITY: size_t = 128;

    // We're not using a Vec for the buffer here to make sure the buffer is allocated and freed by
    // the same allocator.

    let mut decomp = tinfl_decompressor::with_init_state_only();
    // Pointer to the buffer to place the decompressed data into.
    let mut p_buf: *mut c_void = ptr::null_mut();
    // Capacity of the current output buffer.
    let mut out_buf_capacity = 0;

    *p_out_len = 0;
    // How far into the source buffer we have read.
    let mut src_buf_ofs = 0;
    loop {
        let mut out_cur = Cursor::new(slice::from_raw_parts_mut(
            p_buf as *mut u8,
            out_buf_capacity,
        ));
        out_cur.set_position(*p_out_len as u64);
        let (status, in_consumed, out_consumed) =
            decompress(
                &mut decomp,
                slice::from_raw_parts(
                    p_src_buf.offset(src_buf_ofs as isize) as *const u8,
                    src_buf_len - src_buf_ofs,
                ),
                &mut out_cur,
                (flags & !inflate_flags::TINFL_FLAG_HAS_MORE_INPUT) |
                 inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF,
            );

        // If decompression fails or we don't have any input, bail out.
        if (status as i32) < 0 || status == TINFLStatus::NeedsMoreInput {
            ::miniz_def_free_func(ptr::null_mut(), p_buf);
            *p_out_len = 0;
            return ptr::null_mut();
        }

        src_buf_ofs += in_consumed;
        *p_out_len += out_consumed;

        if status == TINFLStatus::Done {
            break;
        }

        // If we need more space, double the capacity of the output buffer
        // and keep going.
        let mut new_out_buf_capacity = out_buf_capacity * 2;

        // Try to get at least 128 bytes of buffer capacity.
        if new_out_buf_capacity < MIN_BUFFER_CAPACITY {
            new_out_buf_capacity = MIN_BUFFER_CAPACITY
        }

        let p_new_buf = ::miniz_def_realloc_func(ptr::null_mut(), p_buf, 1, new_out_buf_capacity);
        // Bail out if growing fails.
        if p_new_buf.is_null() {
            ::miniz_def_free_func(ptr::null_mut(), p_buf);
            *p_out_len = 0;
            return ptr::null_mut();
        }

        // Otherwise, continue using the reallocated buffer.
        p_buf = p_new_buf;
        out_buf_capacity = new_out_buf_capacity;
    }

    p_buf
}
);

#[cfg(test)]
mod test {
    use miniz_oxide::inflate::core::inflate_flags::{
        TINFL_FLAG_COMPUTE_ADLER32,
        TINFL_FLAG_PARSE_ZLIB_HEADER,
    };

    use super::*;
    use libc::c_void;
    use std::{ops, slice};
    /// Safe wrapper for `tinfl_decompress_mem_to_mem` using slices.
    ///
    /// Could maybe make this public later.
    fn tinfl_decompress_mem_to_mem_wrapper(
        source: &mut [u8],
        dest: &mut [u8],
        flags: i32,
    ) -> Option<usize> {
        let status = unsafe {
            let source_len = source.len();
            let dest_len = dest.len();
            tinfl_decompress_mem_to_mem(
                dest.as_mut_ptr() as *mut c_void,
                dest_len,
                source.as_mut_ptr() as *const c_void,
                source_len,
                flags,
            )
        };
        if status != TINFL_DECOMPRESS_MEM_TO_MEM_FAILED {
            Some(status)
        } else {
            None
        }
    }

    /// Safe wrapper around a buffer allocated with the miniz_def functions.
    pub struct TinflHeapBuf {
        buf: *mut c_void,
        len: size_t,
    }

    impl TinflHeapBuf {
        fn as_slice(&self) -> &[u8] {
            unsafe { slice::from_raw_parts(self.buf as *const u8, self.len) }
        }
    }

    impl ops::Drop for TinflHeapBuf {
        fn drop(&mut self) {
            unsafe {
                ::miniz_def_free_func(ptr::null_mut(), self.buf);
            }
        }
    }

    /// Safe wrapper for `tinfl_decompress_mem_to_heap` using slices.
    ///
    /// Could maybe make something like this public later.
    fn tinfl_decompress_mem_to_heap_wrapper(source: &mut [u8], flags: i32) -> Option<TinflHeapBuf> {
        let source_len = source.len();
        let mut out_len = 0;
        unsafe {
            let buf_ptr = tinfl_decompress_mem_to_heap(
                source.as_ptr() as *const c_void,
                source_len,
                &mut out_len,
                flags,
            );
            if !buf_ptr.is_null() {
                Some(TinflHeapBuf {
                    buf: buf_ptr,
                    len: out_len,
                })
            } else {
                None
            }
        }
    }

    #[test]
    fn mem_to_mem() {
        let mut encoded = [
            120, 156, 243, 72, 205, 201, 201, 215, 81, 168,
            202, 201,  76, 82,   4,   0,  27, 101,  4,  19,
        ];
        let mut out_buf = vec![0; 50];
        let flags = TINFL_FLAG_COMPUTE_ADLER32 | TINFL_FLAG_PARSE_ZLIB_HEADER;
        let size = tinfl_decompress_mem_to_mem_wrapper(
            &mut encoded[..],
            out_buf.as_mut_slice(),
            flags as i32,
        ).unwrap();
        assert_eq!(&out_buf[..size], &b"Hello, zlib!"[..]);
    }

    #[test]
    fn mem_to_heap() {
        let mut encoded = [
            120, 156, 243, 72, 205, 201, 201, 215, 81, 168,
            202, 201,  76, 82,   4,   0,  27, 101,  4,  19,
        ];
        let flags = TINFL_FLAG_COMPUTE_ADLER32 | TINFL_FLAG_PARSE_ZLIB_HEADER;
        let out_buf = tinfl_decompress_mem_to_heap_wrapper(&mut encoded[..], flags as i32).unwrap();
        assert_eq!(out_buf.as_slice(), &b"Hello, zlib!"[..]);
    }
}
<commit_msg>use min size starting buffer instead of 0-len in decompress_mem_to_heap<commit_after>#![allow(dead_code)]

use libc::*;
use std::{ptr, slice, usize};
use std::io::Cursor;
use miniz_oxide::inflate::TINFLStatus;
pub use miniz_oxide::inflate::core::{decompress, inflate_flags};
pub use miniz_oxide::inflate::core::DecompressorOxide as tinfl_decompressor;

pub const TINFL_DECOMPRESS_MEM_TO_MEM_FAILED: size_t = usize::MAX;

unmangle!(
pub unsafe extern "C" fn tinfl_decompress(
    r: *mut tinfl_decompressor,
    in_buf: *const u8,
    in_buf_size: *mut usize,
    out_buf_start: *mut u8,
    out_buf_next: *mut u8,
    out_buf_size: *mut usize,
    flags: u32,
) -> i32 {
    let next_pos = out_buf_next as usize - out_buf_start as usize;
    let out_size = *out_buf_size + next_pos;
    let mut out_cursor = Cursor::new(slice::from_raw_parts_mut(out_buf_start, out_size));
    out_cursor.set_position(next_pos as u64);
    let (status, in_consumed, out_consumed) = decompress(
        r.as_mut().expect("bad decompressor pointer"),
        slice::from_raw_parts(in_buf, *in_buf_size),
        &mut out_cursor,
        flags,
    );

    *in_buf_size = in_consumed;
    *out_buf_size = out_consumed;
    status as i32
}

pub unsafe extern "C" fn tinfl_decompress_mem_to_mem(
    p_out_buf: *mut c_void,
    out_buf_len: size_t,
    p_src_buf: *const c_void,
    src_buf_len: size_t,
    flags: c_int,
) -> size_t {
    let flags = flags as u32;
    let mut decomp = tinfl_decompressor::with_init_state_only();

    let (status, _, out_consumed) =
        decompress(
            &mut decomp,
            slice::from_raw_parts(p_src_buf as *const u8, src_buf_len),
            &mut Cursor::new(slice::from_raw_parts_mut(p_out_buf as *mut u8, out_buf_len)),
            (flags & !inflate_flags::TINFL_FLAG_HAS_MORE_INPUT) | inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF,
        );

    if status != TINFLStatus::Done {
        TINFL_DECOMPRESS_MEM_TO_MEM_FAILED as size_t
    } else {
        out_consumed
    }
}

/// Decompress data from `p_src_buf` to a continuously growing heap-allocated buffer.
///
/// Sets `p_out_len` to the length of the returned buffer.
/// Returns `ptr::null()` if decompression or allocation fails.
/// The buffer should be freed with `miniz_def_free_func`.
pub unsafe extern "C" fn tinfl_decompress_mem_to_heap(
    p_src_buf: *const c_void,
    src_buf_len: size_t,
    p_out_len: *mut size_t,
    flags: c_int,
) -> *mut c_void {
    let flags = flags as u32;
    const MIN_BUFFER_CAPACITY: size_t = 128;

    // We're not using a Vec for the buffer here to make sure the buffer is allocated and freed by
    // the same allocator.

    let mut decomp = tinfl_decompressor::with_init_state_only();
    // Pointer to the buffer to place the decompressed data into.
    let mut p_buf: *mut c_void = ::miniz_def_alloc_func(ptr::null_mut(), MIN_BUFFER_CAPACITY, 1);
    // Capacity of the current output buffer.
    let mut out_buf_capacity = MIN_BUFFER_CAPACITY;

    *p_out_len = 0;
    // How far into the source buffer we have read.
    let mut src_buf_ofs = 0;
    loop {
        let mut out_cur = Cursor::new(slice::from_raw_parts_mut(
            p_buf as *mut u8,
            out_buf_capacity,
        ));
        out_cur.set_position(*p_out_len as u64);
        let (status, in_consumed, out_consumed) =
            decompress(
                &mut decomp,
                slice::from_raw_parts(
                    p_src_buf.offset(src_buf_ofs as isize) as *const u8,
                    src_buf_len - src_buf_ofs,
                ),
                &mut out_cur,
                (flags & !inflate_flags::TINFL_FLAG_HAS_MORE_INPUT) |
                 inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF,
            );

        // If decompression fails or we don't have any input, bail out.
        if (status as i32) < 0 || status == TINFLStatus::NeedsMoreInput {
            ::miniz_def_free_func(ptr::null_mut(), p_buf);
            *p_out_len = 0;
            return ptr::null_mut();
        }

        src_buf_ofs += in_consumed;
        *p_out_len += out_consumed;

        if status == TINFLStatus::Done {
            break;
        }

        // If we need more space, double the capacity of the output buffer
        // and keep going.
        let mut new_out_buf_capacity = out_buf_capacity * 2;

        // Try to get at least 128 bytes of buffer capacity.
        if new_out_buf_capacity < MIN_BUFFER_CAPACITY {
            new_out_buf_capacity = MIN_BUFFER_CAPACITY
        }

        let p_new_buf = ::miniz_def_realloc_func(ptr::null_mut(), p_buf, 1, new_out_buf_capacity);
        // Bail out if growing fails.
        if p_new_buf.is_null() {
            ::miniz_def_free_func(ptr::null_mut(), p_buf);
            *p_out_len = 0;
            return ptr::null_mut();
        }

        // Otherwise, continue using the reallocated buffer.
        p_buf = p_new_buf;
        out_buf_capacity = new_out_buf_capacity;
    }

    p_buf
}
);

#[cfg(test)]
mod test {
    use miniz_oxide::inflate::core::inflate_flags::{
        TINFL_FLAG_COMPUTE_ADLER32,
        TINFL_FLAG_PARSE_ZLIB_HEADER,
    };

    use super::*;
    use libc::c_void;
    use std::{ops, slice};
    /// Safe wrapper for `tinfl_decompress_mem_to_mem` using slices.
    ///
    /// Could maybe make this public later.
    fn tinfl_decompress_mem_to_mem_wrapper(
        source: &mut [u8],
        dest: &mut [u8],
        flags: i32,
    ) -> Option<usize> {
        let status = unsafe {
            let source_len = source.len();
            let dest_len = dest.len();
            tinfl_decompress_mem_to_mem(
                dest.as_mut_ptr() as *mut c_void,
                dest_len,
                source.as_mut_ptr() as *const c_void,
                source_len,
                flags,
            )
        };
        if status != TINFL_DECOMPRESS_MEM_TO_MEM_FAILED {
            Some(status)
        } else {
            None
        }
    }

    /// Safe wrapper around a buffer allocated with the miniz_def functions.
    pub struct TinflHeapBuf {
        buf: *mut c_void,
        len: size_t,
    }

    impl TinflHeapBuf {
        fn as_slice(&self) -> &[u8] {
            unsafe { slice::from_raw_parts(self.buf as *const u8, self.len) }
        }
    }

    impl ops::Drop for TinflHeapBuf {
        fn drop(&mut self) {
            unsafe {
                ::miniz_def_free_func(ptr::null_mut(), self.buf);
            }
        }
    }

    /// Safe wrapper for `tinfl_decompress_mem_to_heap` using slices.
    ///
    /// Could maybe make something like this public later.
    fn tinfl_decompress_mem_to_heap_wrapper(source: &mut [u8], flags: i32) -> Option<TinflHeapBuf> {
        let source_len = source.len();
        let mut out_len = 0;
        unsafe {
            let buf_ptr = tinfl_decompress_mem_to_heap(
                source.as_ptr() as *const c_void,
                source_len,
                &mut out_len,
                flags,
            );
            if !buf_ptr.is_null() {
                Some(TinflHeapBuf {
                    buf: buf_ptr,
                    len: out_len,
                })
            } else {
                None
            }
        }
    }

    #[test]
    fn mem_to_mem() {
        let mut encoded = [
            120, 156, 243, 72, 205, 201, 201, 215, 81, 168,
            202, 201,  76, 82,   4,   0,  27, 101,  4,  19,
        ];
        let mut out_buf = vec![0; 50];
        let flags = TINFL_FLAG_COMPUTE_ADLER32 | TINFL_FLAG_PARSE_ZLIB_HEADER;
        let size = tinfl_decompress_mem_to_mem_wrapper(
            &mut encoded[..],
            out_buf.as_mut_slice(),
            flags as i32,
        ).unwrap();
        assert_eq!(&out_buf[..size], &b"Hello, zlib!"[..]);
    }

    #[test]
    fn mem_to_heap() {
        let mut encoded = [
            120, 156, 243, 72, 205, 201, 201, 215, 81, 168,
            202, 201,  76, 82,   4,   0,  27, 101,  4,  19,
        ];
        let flags = TINFL_FLAG_COMPUTE_ADLER32 | TINFL_FLAG_PARSE_ZLIB_HEADER;
        let out_buf = tinfl_decompress_mem_to_heap_wrapper(&mut encoded[..], flags as i32).unwrap();
        assert_eq!(out_buf.as_slice(), &b"Hello, zlib!"[..]);
    }
}
<|endoftext|>


<commit_before>
// A regex "token" represents a single character in the text
// It can be one of:
//     a character literal
//     a character class
//     a any character (.)
#[derive(PartialEq, Debug)]
pub enum Token {
    Literal(char),
    Class(Vec<char>),
    Any
}

#[derive(PartialEq, Debug)]
pub struct Multiplicity {
    minimum: usize,
    maximum: usize
}

// A regex "expression" represents a token with multiplicity, or a position
// Eg. `[abc]*`, `[abc]{1,3}`, `^`
#[derive(PartialEq, Debug)]
pub enum Expression {
    BeginPosition,
    EndPosition,
    Token(Token, Multiplicity)
}

pub fn parse_expressions(text: &str) -> Vec<Expression> {
    let mut result = Vec::new();

    for c in text.chars() {
        match c {
            c => { // Not a meta-character, treat as a literal
                result.push(Expression::Token(
                    Token::Literal(c),
                    Multiplicity {
                        minimum: 1,
                        maximum: 1
                    }
                ));
            }

        }
    }

    result
}

#[cfg(test)]
mod expression_spec {
    use super::{Token, Multiplicity, Expression, parse_expressions};

    #[test]
    fn parses_single_literal() {
        assert_eq!(vec![
                   Expression::Token(
                       Token::Literal('a'),
                       Multiplicity {
                           minimum: 1,
                           maximum: 1
                       }
                   )
        ], parse_expressions("a"))
    }

    #[test]
    fn parses_many_literals() {
        assert_eq!(6, parse_expressions("abcxyz").len());
    }
}

<commit_msg>add ability to parse "?" metacharacter<commit_after>
// A regex "token" represents a single character in the text
// It can be one of:
//     a character literal
//     a character class
//     a any character (.)
#[derive(PartialEq, Debug)]
pub enum Token {
    Literal(char),
    Class(Vec<char>),
    Any
}

#[derive(PartialEq, Debug)]
pub struct Multiplicity {
    minimum: usize,
    maximum: usize
}

// A regex "expression" represents a token with multiplicity, or a position
// Eg. `[abc]*`, `[abc]{1,3}`, `^`
#[derive(PartialEq, Debug)]
pub enum Expression {
    BeginPosition,
    EndPosition,
    Token(Token, Multiplicity)
}

pub fn parse_expressions(text: &str) -> Result<Vec<Expression>,&str> {
    let mut result = Vec::<Expression>::new();

    for c in text.chars() {
        match c {
            '?' => {
                match result.pop() {
                    Some(value) => {
                        match value {
                            Expression::Token(token, multiplicity) => {
                                result.push(Expression::Token(
                                        token,
                                        Multiplicity {
                                            minimum: 0,
                                            maximum: 1
                                        }));
                            },
                            _ => { return Err("invalid token before the `?` metacharacter"); }
                        }},
                    None => { return Err("no token before `?` metacharacter"); }

                }
            },
            c => { // Not a meta-character, treat as a literal
                result.push(Expression::Token(
                    Token::Literal(c),
                    Multiplicity {
                        minimum: 1,
                        maximum: 1
                    }
                ));
            }

        }
    }

    Ok(result)
}

#[cfg(test)]
mod expression_spec {
    use super::{Token, Multiplicity, Expression, parse_expressions};

    #[test]
    fn parses_single_literal() {
        assert_eq!(vec![
                   Expression::Token(
                       Token::Literal('a'),
                       Multiplicity {
                           minimum: 1,
                           maximum: 1
                       }
                   )
        ], parse_expressions("a").unwrap())
    }

    #[test]
    fn parses_many_literals() {
        assert_eq!(6, parse_expressions("abcxyz").unwrap().len());
    }

    #[test]
    fn handles_optional_multiplicity() {
        assert_eq!(vec![
                   Expression::Token(Token::Literal('a'),
                   Multiplicity {
                       minimum: 0,
                       maximum: 1
                   })
        ], parse_expressions("a?").unwrap());

        assert!(parse_expressions("?").is_err());
        assert!(parse_expressions("??").is_err());
    }
}

<|endoftext|>