<commit_before>// Learning.

use term::Term;
use stroke::Stroke;
use words::{LearnWord, Words};

use std::io::Write;

pub struct Learn {
    words: Words,
    term: Term,
}

impl Learn {
    pub fn new(words: Words, term: Term) -> Learn {
        Learn {
            words: words,
            term: term,
        }
    }

    // Consume the learner, returning the wordset contained in it.
    pub fn into_words(self) -> Words {
        self.words
    }

    pub fn run(&mut self) {
        loop {
            // TODO: Check for things that have expired we need to learn.

            let mut word = match self.words.get_learned() {
                None => {
                    match self.words.get_unlearned() {
                        None => {
                            println!("No more words to learn\r");
                            return;
                        },
                        Some(word) => word,
                    }
                }
                Some(word) => word,
            };

            let status = self.single(&mut word);

            // Return the word.
            self.words.push_word(word);

            if status == Status::Stopped {
                break;
            }
        }
    }

    // Learn a single word, updating its timing information based on how well it was learned.
    fn single(&mut self, word: &mut LearnWord) -> Status {
        let counts = self.words.get_counts();

        writeln!(self.term, "\r\nActive: {}, Later: {}, Unlearned: {}, Interval {}\r",
                 counts.active, counts.later, counts.unlearned,
                 humanize_time(word.interval)).unwrap();
        for b in &counts.buckets {
            writeln!(self.term, "  {:-4}: {:4} {}\r", b.name, b.count,
                     stars(65, b.count, counts.active + counts.later)).unwrap();
        }
        writeln!(self.term, "\r").unwrap();
        self.term.flush().unwrap();

        let mut state = Single::new(&mut self.term, word);
        state.run()
    }
}

// Format an interval (in seconds) in terms of nicer units.
fn humanize_time(interval: f64) -> String {
    let mut val = interval;
    for unit in UNITS {
        if val < unit.div {
            return format!("{:.1} {}", val, unit.name);
        }
        val /= unit.div;
    }
    // Out of bounds, return the unmodified time.
    format!("{:.1} seconds", interval)
}

struct UnitEntry {
    name: &'static str,
    div: f64,
}

static UNITS: &'static [UnitEntry] = &[
    UnitEntry{ name: "seconds", div: 60.0 },
    UnitEntry{ name: "minutes", div: 60.0 },
    UnitEntry{ name: "hours", div: 24.0 },
    UnitEntry{ name: "days", div: 365.0 },
    UnitEntry{ name: "months", div: 12.0 },
    UnitEntry{ name: "years", div: 1.0e6 },
];

// Print a line of stars resembling a histogram bar.  `len` is the number of stars to use, a is the
// number in question, and total is the expected total.
fn stars(len: usize, value: usize, total: usize) -> String {
    let mut buf = String::new();
    buf.push('|');
    let thresh = value as f64 / total as f64 * len as f64;
    for i in 0 .. len {
        if (i as f64) < thresh {
            buf.push('*');
        } else {
            buf.push(' ');
        };
    }
    buf.push('|');
    buf
}

struct Single<'t, 'w> {
    term: &'t mut Term,
    word: &'w mut LearnWord,
    user: Vec<Stroke>,
    errors: u32,
}

impl<'t, 'w> Single<'t, 'w> {
    fn new<'tt, 'ww>(term: &'tt mut Term, word: &'ww mut LearnWord) -> Single<'tt, 'ww> {
        Single {
            term: term,
            word: word,
            user: vec![],
            errors: 0,
        }
    }

    fn prompt(&mut self) {
        write!(self.term, "\r\x1b[J{:20}: {}{}",
               self.word.english,
               if self.word.strokes == self.user {
                   if self.errors == 0 { '✓' } else { '✗' }
               } else { ' ' },
               slashed(&self.user)).unwrap();
        if self.errors > 0 {
            write!(self.term, "  ({})", slashed(&self.word.strokes)).unwrap();
        }
        self.term.flush().unwrap();
    }

    fn run(&mut self) -> Status {
        let mut result = Status::Continue;
        loop {
            self.prompt();
            if self.word.strokes == self.user {
                break;
            }

            let stroke = match self.term.read_stroke().unwrap() {
                None => { result = Status::Stopped; break; }
                Some(st) => st,
            };
            if stroke.is_star() {
                self.user.pop();
            } else {
                self.user.push(stroke);
                let pos = self.user.len();
                if pos > self.word.strokes.len() ||
                    self.user[pos-1] != self.word.strokes[pos-1]
                {
                    self.errors += 1;
                }
            }
        }

        if result == Status::Continue {
            if self.errors > 0 {
                self.word.incorrect();
            } else {
                self.word.correct();
            }

            writeln!(self.term, "\r\nNew interval {}\r", humanize_time(self.word.interval)).unwrap();
        } else {
            writeln!(self.term, "\r").unwrap();
        }
        self.term.flush().unwrap();
        result
    }
}

// Generate a slash separated version of the given stroke list.
fn slashed(strokes: &[Stroke]) -> String {
    let mut buf = vec![];
    let mut first = true;

    for st in strokes {
        if !first {
            buf.push(b'/');
        }
        first = false;
        write!(&mut buf, "{}", st).unwrap();
    }
    String::from_utf8(buf).unwrap()
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Status {
    Continue,
    Stopped,
}
<commit_msg>Add color output for errors<commit_after>// Learning.

use term::Term;
use stroke::Stroke;
use words::{LearnWord, Words};

use std::io::Write;
use termion::color;

pub struct Learn {
    words: Words,
    term: Term,
}

impl Learn {
    pub fn new(words: Words, term: Term) -> Learn {
        Learn {
            words: words,
            term: term,
        }
    }

    // Consume the learner, returning the wordset contained in it.
    pub fn into_words(self) -> Words {
        self.words
    }

    pub fn run(&mut self) {
        loop {
            // TODO: Check for things that have expired we need to learn.

            let mut word = match self.words.get_learned() {
                None => {
                    match self.words.get_unlearned() {
                        None => {
                            println!("No more words to learn\r");
                            return;
                        },
                        Some(word) => word,
                    }
                }
                Some(word) => word,
            };

            let status = self.single(&mut word);

            // Return the word.
            self.words.push_word(word);

            if status == Status::Stopped {
                break;
            }
        }
    }

    // Learn a single word, updating its timing information based on how well it was learned.
    fn single(&mut self, word: &mut LearnWord) -> Status {
        let counts = self.words.get_counts();

        writeln!(self.term, "\r\nActive: {}, Later: {}, Unlearned: {}, Interval {}\r",
                 counts.active, counts.later, counts.unlearned,
                 humanize_time(word.interval)).unwrap();
        for b in &counts.buckets {
            writeln!(self.term, "  {:-4}: {:4} {}\r", b.name, b.count,
                     stars(65, b.count, counts.active + counts.later)).unwrap();
        }
        writeln!(self.term, "\r").unwrap();
        self.term.flush().unwrap();

        let mut state = Single::new(&mut self.term, word);
        state.run()
    }
}

// Format an interval (in seconds) in terms of nicer units.
fn humanize_time(interval: f64) -> String {
    let mut val = interval;
    for unit in UNITS {
        if val < unit.div {
            return format!("{:.1} {}", val, unit.name);
        }
        val /= unit.div;
    }
    // Out of bounds, return the unmodified time.
    format!("{:.1} seconds", interval)
}

struct UnitEntry {
    name: &'static str,
    div: f64,
}

static UNITS: &'static [UnitEntry] = &[
    UnitEntry{ name: "seconds", div: 60.0 },
    UnitEntry{ name: "minutes", div: 60.0 },
    UnitEntry{ name: "hours", div: 24.0 },
    UnitEntry{ name: "days", div: 365.0 },
    UnitEntry{ name: "months", div: 12.0 },
    UnitEntry{ name: "years", div: 1.0e6 },
];

// Print a line of stars resembling a histogram bar.  `len` is the number of stars to use, a is the
// number in question, and total is the expected total.
fn stars(len: usize, value: usize, total: usize) -> String {
    let mut buf = String::new();
    buf.push('|');
    let thresh = value as f64 / total as f64 * len as f64;
    for i in 0 .. len {
        if (i as f64) < thresh {
            buf.push('*');
        } else {
            buf.push(' ');
        };
    }
    buf.push('|');
    buf
}

struct Single<'t, 'w> {
    term: &'t mut Term,
    word: &'w mut LearnWord,
    user: Vec<Stroke>,
    errors: u32,
}

impl<'t, 'w> Single<'t, 'w> {
    fn new<'tt, 'ww>(term: &'tt mut Term, word: &'ww mut LearnWord) -> Single<'tt, 'ww> {
        Single {
            term: term,
            word: word,
            user: vec![],
            errors: 0,
        }
    }

    fn prompt(&mut self) {
        write!(self.term, "\r\x1b[J{:20}: {}{}",
               self.word.english,
               if self.word.strokes == self.user {
                   if self.errors == 0 { '✓' } else { '✗' }
               } else { ' ' },
               slashed(&self.user, &self.word.strokes)).unwrap();
        if self.errors > 0 {
            write!(self.term, "  ({})", slashed(&self.word.strokes, &self.word.strokes)).unwrap();
        }
        self.term.flush().unwrap();
    }

    fn run(&mut self) -> Status {
        let mut result = Status::Continue;
        loop {
            self.prompt();
            if self.word.strokes == self.user {
                break;
            }

            let stroke = match self.term.read_stroke().unwrap() {
                None => { result = Status::Stopped; break; }
                Some(st) => st,
            };
            if stroke.is_star() {
                self.user.pop();
            } else {
                self.user.push(stroke);
                let pos = self.user.len();
                if pos > self.word.strokes.len() ||
                    self.user[pos-1] != self.word.strokes[pos-1]
                {
                    self.errors += 1;
                }
            }
        }

        if result == Status::Continue {
            if self.errors > 0 {
                self.word.incorrect();
            } else {
                self.word.correct();
            }

            writeln!(self.term, "\r\nNew interval {}\r", humanize_time(self.word.interval)).unwrap();
        } else {
            writeln!(self.term, "\r").unwrap();
        }
        self.term.flush().unwrap();
        result
    }
}

// Generate a slash separated version of the given stroke list.
fn slashed(strokes: &[Stroke], expected: &[Stroke]) -> String {
    let mut buf = vec![];
    let mut first = true;

    for (i, st) in strokes.iter().enumerate() {
        if !first {
            buf.push(b'/');
        }
        first = false;

        let correct = expected.get(i) == Some(st);
        if !correct {
            write!(&mut buf, "{}{}",
                   color::Bg(color::LightRed),
                   color::Fg(color::Black)).unwrap();
        }
        write!(&mut buf, "{}", st).unwrap();
        if !correct {
            write!(&mut buf, "{}{}",
                   color::Bg(color::Reset),
                   color::Fg(color::Reset)).unwrap();
        }
    }
    String::from_utf8(buf).unwrap()
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Status {
    Continue,
    Stopped,
}
<|endoftext|>


<commit_before>use std::str::CharIndices;
use std::iter::Peekable;

#[derive(Debug, PartialEq)]
pub enum Token {
	Identifier(String),
	Value(i32),
}

pub fn tokenize(input: &str) -> Vec<Token> {

	let mut lexer = Lexer::new(input);
	let mut output = vec![];

	loop {

		match lexer.next() {
			Some(t) => {

				output.push(t);

			}
			None => break
		}
	}
	output
}

pub struct Lexer<'a> {
	input: &'a str,
	iter: Peekable<CharIndices<'a>>,
	pos: usize,
	line: u32,
	column: u32,
}

impl<'a> Lexer<'a> {
	fn new(input : &str) -> Lexer {
		Lexer {
			input: input,
			iter: input.char_indices().peekable(),
			pos: 0,
			line: 1,
			column: 1
		}
	}
	fn advance(&mut self) -> Option<char> {

		if let Some((i, c)) = self.iter.next() {
			match c  {
				'\n' => {
					self.column = 1;
					self.line  += 1;
				},

				'\t' => {
					self.column  += 4;

				},
				_ => self.column += 1

			}
			self.pos = i + 1;
			return Some(c);
		}
		None
	}
	fn advance_while<P: Fn(char)-> bool>(&mut self, p: P) {
		loop {

			match self.peek() {
				Some(c) => {

					match p(c) {
						false => break,
						true => {}
					}
				}
				None => break
			}
			self.advance();
		}
	}
	fn peek(&mut self) -> Option<char> {
		if let Some(&(_, c)) = self.iter.peek() {
			return Some(c);
		}
		None
	}
	fn handle_alphabetic(&mut self) -> Token {
		let start = self.pos;
		self.advance_while(is_alphabetic);

		Token::Identifier(self.input[start..self.pos].to_string())
	}
	fn handle_number(&mut self) -> Token {
		let start = self.pos;
		self.advance_while(is_numeric);

		Token::Value(self.input[start..self.pos].parse().unwrap())
	}

	fn handle_whitespace(&mut self) {
		self.advance_while(is_whitespace);
	}
}

impl<'a> Iterator for Lexer<'a> {
	type Item = Token;
	fn next(&mut self) -> Option<Token> {

		let token = match self.peek() {
			Some(c) if is_alphabetic(c) => self.handle_alphabetic(),
			Some(c) if is_numeric(c) => self.handle_number(),
			Some(c) if is_whitespace(c) => {
				self.handle_whitespace();
				match self.next() {
					Some(t) => return Some(t),
					None => return None,
				}
			},
			None => return None,
			_ =>  return None,

		};
		Some(token)

	}
}

fn is_numeric(c: char) -> bool {
	match c {
		'0'...'9' => true,
		_ => false
	}
}
fn is_alphabetic(c: char) -> bool {
	match c {
		'a' ... 'z' | 'A' ... 'Z' | ':' => true,
		_ => false
	}
}
fn is_whitespace(c: char) -> bool {
	match c {
		' ' | '\t' | '\n' => true,
		_ => false
	}
}
fn is_comment(c: char) -> bool {
	match c {
		'#' => true,
		_ => false
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use super::{is_numeric, is_alphabetic};
	#[test]
	fn advance(){
		let mut lexer = Lexer::new("test 14 @\ntesting\ntest\ttesting");
		let mut output = String::new();

		loop {
			match lexer.advance() {
				Some(c) => {
					output.push(c);

				},
				None => break
			}
		}
		assert_eq!(output, "test 14 @\ntesting\ntest\ttesting");
		assert_eq!(lexer.line, 3);
		assert_eq!(lexer.column, 16);
	}
	#[test]
	fn advance_while_numeric(){
		let mut lexer = Lexer::new("4532test s34");
		let start = lexer.pos;
		lexer.advance_while(is_numeric);
		assert_eq!(&lexer.input[start..lexer.pos], "4532");
	}
	#[test]
	fn advance_while_alphabetic(){
		let mut lexer = Lexer::new("test3 3test");
		let start = lexer.pos;
		lexer.advance_while(is_alphabetic);
		assert_eq!(&lexer.input[start..lexer.pos], "test");
	}
	#[test]
	fn peek(){
		let mut lexer = Lexer::new("The quick brown fox jumps over the 64 lazy dog");
		let mut output = String::new();

		loop {

			match lexer.peek() {
				Some(c) => {
					output.push(c);

				}
				None => break
			}
			lexer.advance();
		}
		assert_eq!(output, "The quick brown fox jumps over the 64 lazy dog");

	}
	#[test]
	fn iter(){
		let mut lexer = Lexer::new("The 42\n 42");
		let mut output = vec![];

		loop {
			match lexer.next() {
				Some(t) => {

					output.push(t);

				}
				None => break
			}
		}
		assert_eq!(output, vec![Token::Identifier("The".to_string()), Token::Value(42), Token::Value(42)]);
	}

}

<commit_msg>handle comments<commit_after>use std::str::CharIndices;
use std::iter::Peekable;

#[derive(Debug, PartialEq)]
pub enum Token {
	Identifier(String),
	Value(i32),
}

pub fn tokenize(input: &str) -> Vec<Token> {

	let mut lexer = Lexer::new(input);
	let mut output = vec![];

	loop {

		match lexer.next() {
			Some(t) => {

				output.push(t);

			}
			None => break
		}
	}
	output
}

pub struct Lexer<'a> {
	input: &'a str,
	iter: Peekable<CharIndices<'a>>,
	pos: usize,
	line: u32,
	column: u32,
}

impl<'a> Lexer<'a> {
	fn new(input : &str) -> Lexer {
		Lexer {
			input: input,
			iter: input.char_indices().peekable(),
			pos: 0,
			line: 1,
			column: 1
		}
	}
	fn advance(&mut self) -> Option<char> {

		if let Some((i, c)) = self.iter.next() {
			match c  {
				'\n' => {
					self.column = 1;
					self.line  += 1;
				},

				'\t' => {
					self.column  += 4;

				},
				_ => self.column += 1

			}
			self.pos = i + 1;
			return Some(c);
		}
		None
	}
	fn advance_while<P: Fn(char)-> bool>(&mut self, p: P) {
		loop {

			match self.peek() {
				Some(c) => {

					match p(c) {
						false => break,
						true => {}
					}
				}
				None => break
			}
			self.advance();
		}
	}
	fn peek(&mut self) -> Option<char> {
		if let Some(&(_, c)) = self.iter.peek() {
			return Some(c);
		}
		None
	}
	fn handle_alphabetic(&mut self) -> Token {
		let start = self.pos;
		self.advance_while(is_alphabetic);

		Token::Identifier(self.input[start..self.pos].to_string())
	}
	fn handle_number(&mut self) -> Token {
		let start = self.pos;
		self.advance_while(is_numeric);

		Token::Value(self.input[start..self.pos].parse().unwrap())
	}

	fn handle_whitespace(&mut self) {
		self.advance_while(is_whitespace);
	}
	fn handle_comment(&mut self) {
		self.advance_while(|ch| ch != '\n');

	}
}

impl<'a> Iterator for Lexer<'a> {
	type Item = Token;
	fn next(&mut self) -> Option<Token> {

		let token = match self.peek() {
			Some(c) if is_alphabetic(c) => self.handle_alphabetic(),
			Some(c) if is_numeric(c) => self.handle_number(),
			Some(c) if is_whitespace(c) => {
				self.handle_whitespace();
				match self.next() {
					Some(t) => return Some(t),
					None => return None,
				}
			},
			Some(c) if is_comment(c) => {
				self.handle_comment();
				match self.next() {
					Some(t) => return Some(t),
					None => return None,
				}
			},
			None => return None,
			_ =>  return None,

		};
		Some(token)

	}
}

fn is_numeric(c: char) -> bool {
	match c {
		'0'...'9' => true,
		_ => false
	}
}
fn is_alphabetic(c: char) -> bool {
	match c {
		'a' ... 'z' | 'A' ... 'Z' | ':' => true,
		_ => false
	}
}
fn is_whitespace(c: char) -> bool {
	match c {
		' ' | '\t' | '\n' | '\r' => true,
		_ => false
	}
}
fn is_comment(c: char) -> bool {
	match c {
		'#' => true,
		_ => false
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use super::{is_numeric, is_alphabetic};
	#[test]
	fn advance(){
		let mut lexer = Lexer::new("test 14 @\ntesting\ntest\ttesting");
		let mut output = String::new();

		loop {
			match lexer.advance() {
				Some(c) => {
					output.push(c);

				},
				None => break
			}
		}
		assert_eq!(output, "test 14 @\ntesting\ntest\ttesting");
		assert_eq!(lexer.line, 3);
		assert_eq!(lexer.column, 16);
	}
	#[test]
	fn handle_comment(){
		let mut lexer = Lexer::new("psh 7# pushes 7\n psh 8");
		let mut  output = vec![];

		loop {
			match lexer.next() {
				Some(c) => {
					output.push(c);

				},
				None => break
			}
		}
		assert_eq!(output, vec![Token::Identifier("psh".to_string()), Token::Value(7), Token::Identifier("psh".to_string()), Token::Value(8)]);
	}
	#[test]
	fn advance_while_numeric(){
		let mut lexer = Lexer::new("4532test s34");
		let start = lexer.pos;
		lexer.advance_while(is_numeric);
		assert_eq!(&lexer.input[start..lexer.pos], "4532");
	}

	#[test]
	fn advance_while_alphabetic(){
		let mut lexer = Lexer::new("test3 3test");
		let start = lexer.pos;
		lexer.advance_while(is_alphabetic);
		assert_eq!(&lexer.input[start..lexer.pos], "test");
	}
	#[test]
	fn peek(){
		let mut lexer = Lexer::new("The quick brown fox jumps over the 64 lazy dog");
		let mut output = String::new();

		loop {

			match lexer.peek() {
				Some(c) => {
					output.push(c);

				}
				None => break
			}
			lexer.advance();
		}
		assert_eq!(output, "The quick brown fox jumps over the 64 lazy dog");

	}
	#[test]
	fn iter(){
		let mut lexer = Lexer::new("The 42\n 42");
		let mut output = vec![];

		loop {
			match lexer.next() {
				Some(t) => {

					output.push(t);

				}
				None => break
			}
		}
		assert_eq!(output, vec![Token::Identifier("The".to_string()), Token::Value(42), Token::Value(42)]);
	}

}

<|endoftext|>


<commit_before>use std::io::{BufReader, BufferedReader, Reader};
use std::str::{from_char, with_capacity};
use std::char::from_u32;
use std::num::FromStrRadix;
use ast::{TIdent, TNumber, TString, TSemicolon, TColon, TDot, TEqual, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TNumOp, TBitOp};
use ast::{OpAdd, OpSub, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor};
use ast::Token;
use std::io::{IoResult, EndOfFile};
#[deriving(Clone)]
#[deriving(Eq)]
#[deriving(Show)]
/// The type of string used
pub enum StringType {
	/// Double-quoted
	DoubleQuote,
	/// Single-quoted
	SingleQuote
}
/// The Javascript Lexer
pub struct Lexer {
	/// The list of tokens generated so far
	pub tokens : Vec<Token>,
	/// The string buffer for identities
	ident_buffer : ~str,
	/// The string buffer for strings
	string_buffer : ~str,
	/// The string buffer for numbers
	num_buffer : ~str,
	/// The kind of string - i.e. double quote or single quote or none if it isn't in a string
	string_start : Option<StringType>,
	/// If the lexer is currently inside a number
	in_num : bool,
	/// If a backwards slash has just been read
	escaped : bool
}
impl Lexer {
	/// Creates a new lexer with empty buffers
	pub fn new() -> ~Lexer {
		return ~Lexer {
			tokens: Vec::new(),
			ident_buffer: with_capacity(32),
			string_buffer: with_capacity(256),
			num_buffer: with_capacity(16),
			string_start: None,
			in_num: false,
			escaped: false
		};
	}
	fn clear_buffer(&mut self) {
		if self.ident_buffer.len() > 0 {
			self.tokens.push(TIdent(self.ident_buffer.clone()));
			self.ident_buffer.clear();
		}
		if self.in_num {
			self.tokens.push(TNumber(from_str(self.num_buffer).unwrap()));
			self.num_buffer.clear();
			self.in_num = false;
		}
	}
	/// Processes an input stream from a string into an array of tokens
	pub fn lex_str(&mut self, script:~str) -> IoResult<()> {
		let script_bytes:&[u8] = script.as_bytes();
		let reader = BufReader::new(script_bytes);
		let buf_reader = BufferedReader::new(reader);
		self.lex(buf_reader)
	}
	/// Processes an input stream from a BufferedReader into an array of tokens
	pub fn lex<R : Reader>(&mut self, mut reader : BufferedReader<R>) -> IoResult<()> {
		loop {
			let ch = match reader.read_char() {
				Ok(c) => c,
				Err(ref e) if e.kind == EndOfFile => {
					self.clear_buffer();
					return Ok(())
				},
				Err(ref e) =>
					return Err(e.clone())
			};
			match ch {
				_ if self.escaped => {
					self.escaped = false;
					if ch != '\n' {
						self.string_buffer = self.string_buffer + from_char(match ch {
							'n' => '\n',
							'r' => '\r',
							't' => '\t',
							'b' => '\x08',
							'f' => '\x0c',
							'0' => '\0',
							'u' => {
								let mut nums = ~"";
								for _ in range(0, 4) {
									nums = format!("{}{}", nums, reader.read_char().unwrap());
								}
								from_u32(FromStrRadix::from_str_radix(nums, 16).unwrap()).unwrap()
							},
							'\'' if self.string_start == Some(SingleQuote) => '\'',
							'"' if self.string_start == Some(DoubleQuote) => '"',
							_ => fail!("Invalid escape `{}` after {}", ch, self.string_start)
						});
					}
				},
				'"' if self.string_start.is_some() && self.string_start.unwrap() == DoubleQuote => {
					self.string_start = None;
					self.tokens.push(TString(self.string_buffer.clone()));
					self.string_buffer.clear();
				},
				'\'' if self.string_start.is_some() && self.string_start.unwrap() == SingleQuote => {
					self.string_start = None;
					self.tokens.push(TString(self.string_buffer.clone()));
					self.string_buffer.clear();
				},
				'\\' if self.string_start.is_some() => self.escaped = true,
				_ if self.string_start.is_some() => self.string_buffer = format!("{}{}", self.string_buffer, ch),
				'"' if self.string_start.is_none() => self.string_start = Some(DoubleQuote),
				'0'.. '9' if self.string_start.is_none() && self.ident_buffer.len() == 0 => {
					self.num_buffer = format!("{}{}", self.num_buffer.clone(), ch);
					self.in_num = true;
				},
				'\'' if self.string_start.is_none() => self.string_start = Some(SingleQuote),
				'.' if self.in_num && !self.num_buffer.contains(".") => {
					self.num_buffer = format!("{}{}", self.num_buffer, ch);
				},
				';' => {
					self.clear_buffer();
					self.tokens.push(TSemicolon)
				},
				':' => {
					self.clear_buffer();
					self.tokens.push(TColon)
				},
				'.' => {
					self.clear_buffer();
					self.tokens.push(TDot)
				},
				'(' => {
					self.clear_buffer();
					self.tokens.push(TOpenParen)
				},
				')' => {
					self.clear_buffer();
					self.tokens.push(TCloseParen)
				},
				',' => {
					self.clear_buffer();
					self.tokens.push(TComma)
				},
				'{' => {
					self.clear_buffer();
					self.tokens.push(TOpenBlock)
				},
				'}' => {
					self.clear_buffer();
					self.tokens.push(TCloseBlock)
				},
				'[' => {
					self.clear_buffer();
					self.tokens.push(TOpenArray)
				},
				']' => {
					self.clear_buffer();
					self.tokens.push(TCloseArray)
				},
				'?' => {
					self.clear_buffer();
					self.tokens.push(TQuestion)
				},
				'/' => {
					self.clear_buffer();
					self.tokens.push(TNumOp(OpDiv))
				},
				'*' => {
					self.clear_buffer();
					self.tokens.push(TNumOp(OpMul))
				},
				'+' => {
					self.clear_buffer();
					self.tokens.push(TNumOp(OpAdd))
				},
				'-' => {
					self.clear_buffer();
					self.tokens.push(TNumOp(OpSub))
				},
				'%' => {
					self.clear_buffer();
					self.tokens.push(TNumOp(OpMod))
				},
				'|' => {
					self.clear_buffer();
					self.tokens.push(TBitOp(BitOr))
				},
				'&' => {
					self.clear_buffer();
					self.tokens.push(TBitOp(BitAnd))
				},
				'^' => {
					self.clear_buffer();
					self.tokens.push(TBitOp(BitXor))
				},
				'=' => {
					self.clear_buffer();
					self.tokens.push(TEqual)
				},
				' ' | '\t' | '\n' => self.clear_buffer(),
				_ => self.ident_buffer = format!("{}{}", self.ident_buffer, ch)
			};
		}
	}
}<commit_msg>More verbose error messages<commit_after>use std::io::{BufReader, BufferedReader, Reader};
use std::str::{from_char, with_capacity};
use std::char::from_u32;
use std::num::FromStrRadix;
use ast::{TIdent, TNumber, TString, TSemicolon, TColon, TDot, TEqual, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TNumOp, TBitOp};
use ast::{OpAdd, OpSub, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor};
use ast::Token;
use std::io::{IoResult, EndOfFile};
#[deriving(Clone)]
#[deriving(Eq)]
#[deriving(Show)]
/// The type of string used
pub enum StringType {
	/// Double-quoted
	DoubleQuote,
	/// Single-quoted
	SingleQuote
}
/// The Javascript Lexer
pub struct Lexer {
	/// The list of tokens generated so far
	pub tokens : Vec<Token>,
	/// The string buffer for identities
	ident_buffer : ~str,
	/// The string buffer for strings
	string_buffer : ~str,
	/// The string buffer for numbers
	num_buffer : ~str,
	/// The kind of string - i.e. double quote or single quote or none if it isn't in a string
	string_start : Option<StringType>,
	/// If the lexer is currently inside a number
	in_num : bool,
	/// If a backwards slash has just been read
	escaped : bool
}
impl Lexer {
	/// Creates a new lexer with empty buffers
	pub fn new() -> ~Lexer {
		return ~Lexer {
			tokens: Vec::new(),
			ident_buffer: with_capacity(32),
			string_buffer: with_capacity(256),
			num_buffer: with_capacity(16),
			string_start: None,
			in_num: false,
			escaped: false
		};
	}
	fn clear_buffer(&mut self) {
		if self.ident_buffer.len() > 0 {
			self.tokens.push(TIdent(self.ident_buffer.clone()));
			self.ident_buffer.clear();
		}
		if self.in_num {
			self.tokens.push(TNumber(from_str(self.num_buffer).unwrap()));
			self.num_buffer.clear();
			self.in_num = false;
		}
	}
	/// Processes an input stream from a string into an array of tokens
	pub fn lex_str(&mut self, script:~str) -> IoResult<()> {
		let script_bytes:&[u8] = script.as_bytes();
		let reader = BufReader::new(script_bytes);
		let buf_reader = BufferedReader::new(reader);
		self.lex(buf_reader)
	}
	/// Processes an input stream from a BufferedReader into an array of tokens
	pub fn lex<R : Reader>(&mut self, mut reader : BufferedReader<R>) -> IoResult<()> {
		loop {
			let ch = match reader.read_char() {
				Ok(c) => c,
				Err(ref e) if e.kind == EndOfFile => {
					self.clear_buffer();
					return Ok(())
				},
				Err(ref e) =>
					return Err(e.clone())
			};
			match ch {
				_ if self.escaped => {
					self.escaped = false;
					if ch != '\n' {
						self.string_buffer = self.string_buffer + from_char(match ch {
							'n' => '\n',
							'r' => '\r',
							't' => '\t',
							'b' => '\x08',
							'f' => '\x0c',
							'0' => '\0',
							'u' => {
								let mut nums = ~"";
								for _ in range(0, 4) {
									nums = format!("{}{}", nums, try!(reader.read_char()));
								}
								let as_num = match FromStrRadix::from_str_radix(nums, 16) {
									Some(v) => v,
									None => 0
								};
								match from_u32(as_num) {
									Some(v) => v,
									None => fail!("{} is not a valid unicode scalar value", as_num)
								}
							},
							'\'' if self.string_start == Some(SingleQuote) => '\'',
							'"' if self.string_start == Some(DoubleQuote) => '"',
							_ => fail!("Invalid escape `{}` after {}", ch, self.string_start)
						});
					}
				},
				'"' if self.string_start.is_some() && self.string_start.unwrap() == DoubleQuote => {
					self.string_start = None;
					self.tokens.push(TString(self.string_buffer.clone()));
					self.string_buffer.clear();
				},
				'\'' if self.string_start.is_some() && self.string_start.unwrap() == SingleQuote => {
					self.string_start = None;
					self.tokens.push(TString(self.string_buffer.clone()));
					self.string_buffer.clear();
				},
				'\\' if self.string_start.is_some() => self.escaped = true,
				_ if self.string_start.is_some() => self.string_buffer = format!("{}{}", self.string_buffer, ch),
				'"' if self.string_start.is_none() => self.string_start = Some(DoubleQuote),
				'0'.. '9' if self.string_start.is_none() && self.ident_buffer.len() == 0 => {
					self.num_buffer = format!("{}{}", self.num_buffer.clone(), ch);
					self.in_num = true;
				},
				'\'' if self.string_start.is_none() => self.string_start = Some(SingleQuote),
				'.' if self.in_num && !self.num_buffer.contains(".") => {
					self.num_buffer = format!("{}{}", self.num_buffer, ch);
				},
				';' => {
					self.clear_buffer();
					self.tokens.push(TSemicolon)
				},
				':' => {
					self.clear_buffer();
					self.tokens.push(TColon)
				},
				'.' => {
					self.clear_buffer();
					self.tokens.push(TDot)
				},
				'(' => {
					self.clear_buffer();
					self.tokens.push(TOpenParen)
				},
				')' => {
					self.clear_buffer();
					self.tokens.push(TCloseParen)
				},
				',' => {
					self.clear_buffer();
					self.tokens.push(TComma)
				},
				'{' => {
					self.clear_buffer();
					self.tokens.push(TOpenBlock)
				},
				'}' => {
					self.clear_buffer();
					self.tokens.push(TCloseBlock)
				},
				'[' => {
					self.clear_buffer();
					self.tokens.push(TOpenArray)
				},
				']' => {
					self.clear_buffer();
					self.tokens.push(TCloseArray)
				},
				'?' => {
					self.clear_buffer();
					self.tokens.push(TQuestion)
				},
				'/' => {
					self.clear_buffer();
					self.tokens.push(TNumOp(OpDiv))
				},
				'*' => {
					self.clear_buffer();
					self.tokens.push(TNumOp(OpMul))
				},
				'+' => {
					self.clear_buffer();
					self.tokens.push(TNumOp(OpAdd))
				},
				'-' => {
					self.clear_buffer();
					self.tokens.push(TNumOp(OpSub))
				},
				'%' => {
					self.clear_buffer();
					self.tokens.push(TNumOp(OpMod))
				},
				'|' => {
					self.clear_buffer();
					self.tokens.push(TBitOp(BitOr))
				},
				'&' => {
					self.clear_buffer();
					self.tokens.push(TBitOp(BitAnd))
				},
				'^' => {
					self.clear_buffer();
					self.tokens.push(TBitOp(BitXor))
				},
				'=' => {
					self.clear_buffer();
					self.tokens.push(TEqual)
				},
				' ' | '\t' | '\n' => self.clear_buffer(),
				_ => self.ident_buffer = format!("{}{}", self.ident_buffer, ch)
			};
		}
	}
}<|endoftext|>


<commit_before>use crate::syscalls;
use core::slice;

// Setting the break is marked as unsafe as it should only be called by the entry point to setup
// the allocator. Updating the break afterwards can lead to allocated memory becoming unaccessible.
//
// Alternate allocator implementations may still find this useful in the future.
pub unsafe fn set_brk(ptr: *const u8) -> bool {
    syscalls::memop(0, ptr as usize) == 0
}

pub unsafe fn increment_brk(increment: usize) -> Option<*const u8> {
    let result = syscalls::memop(1, increment);
    if result >= 0 {
        Some(result as *const u8)
    } else {
        None
    }
}

pub fn get_brk() -> *const u8 {
    unsafe { syscalls::memop(1, 0) as *const u8 }
}

pub fn get_mem_start() -> *const u8 {
    unsafe { syscalls::memop(2, 0) as *const u8 }
}

pub fn get_mem_end() -> *const u8 {
    unsafe { syscalls::memop(3, 0) as *const u8 }
}

pub fn get_flash_start() -> *const u8 {
    unsafe { syscalls::memop(4, 0) as *const u8 }
}

pub fn get_flash_end() -> *const u8 {
    unsafe { syscalls::memop(5, 0) as *const u8 }
}

pub fn get_grant_start() -> *const u8 {
    unsafe { syscalls::memop(6, 0) as *const u8 }
}

pub fn get_flash_regions_count() -> usize {
    unsafe { syscalls::memop(7, 0) as usize }
}

pub fn get_flash_region_start(i: usize) -> Option<*const u8> {
    if i < get_flash_regions_count() {
        Some(unsafe { syscalls::memop(8, i) as *const u8 })
    } else {
        None
    }
}

pub fn get_flash_region_end(i: usize) -> Option<*const u8> {
    if i < get_flash_regions_count() {
        Some(unsafe { syscalls::memop(9, i) as *const u8 })
    } else {
        None
    }
}

// It is safe to return a 'static immutable slice, as the Tock kernel doesn't change the layout of
// flash regions during the application's lifetime.
pub fn get_flash_region(i: usize) -> Option<&'static [u8]> {
    if i < get_flash_regions_count() {
        let start = unsafe { syscalls::memop(8, i) as *const u8 };
        let end = unsafe { syscalls::memop(9, i) as *const u8 };
        // This assumes that the kernel sends consistent results, i.e. start <= end.
        let len = unsafe { end.offset_from(start) } as usize;
        Some(unsafe { slice::from_raw_parts(start, len) })
    } else {
        None
    }
}

// Setting the stack_top and heap_start addresses are marked as unsafe as they should only be called
// by the entry point to setup the allocator. Updating these values afterwards can lead to incorrect
// debug output from the kernel.
//
// Alternate allocator implementations may still find this useful in the future.
pub unsafe fn set_stack_top(ptr: *const u8) {
    let _ = syscalls::memop(10, ptr as usize);
}

pub unsafe fn set_heap_start(ptr: *const u8) {
    let _ = syscalls::memop(11, ptr as usize);
}
<commit_msg>Add reference to the last tested Tock version and relevant docs.<commit_after>// Last updated for Tock 1.4.
// See https://github.com/tock/tock/blob/master/doc/syscalls/memop.md
use crate::syscalls;
use core::slice;

// Setting the break is marked as unsafe as it should only be called by the entry point to setup
// the allocator. Updating the break afterwards can lead to allocated memory becoming unaccessible.
//
// Alternate allocator implementations may still find this useful in the future.
pub unsafe fn set_brk(ptr: *const u8) -> bool {
    syscalls::memop(0, ptr as usize) == 0
}

pub unsafe fn increment_brk(increment: usize) -> Option<*const u8> {
    let result = syscalls::memop(1, increment);
    if result >= 0 {
        Some(result as *const u8)
    } else {
        None
    }
}

pub fn get_brk() -> *const u8 {
    unsafe { syscalls::memop(1, 0) as *const u8 }
}

pub fn get_mem_start() -> *const u8 {
    unsafe { syscalls::memop(2, 0) as *const u8 }
}

pub fn get_mem_end() -> *const u8 {
    unsafe { syscalls::memop(3, 0) as *const u8 }
}

pub fn get_flash_start() -> *const u8 {
    unsafe { syscalls::memop(4, 0) as *const u8 }
}

pub fn get_flash_end() -> *const u8 {
    unsafe { syscalls::memop(5, 0) as *const u8 }
}

pub fn get_grant_start() -> *const u8 {
    unsafe { syscalls::memop(6, 0) as *const u8 }
}

pub fn get_flash_regions_count() -> usize {
    unsafe { syscalls::memop(7, 0) as usize }
}

pub fn get_flash_region_start(i: usize) -> Option<*const u8> {
    if i < get_flash_regions_count() {
        Some(unsafe { syscalls::memop(8, i) as *const u8 })
    } else {
        None
    }
}

pub fn get_flash_region_end(i: usize) -> Option<*const u8> {
    if i < get_flash_regions_count() {
        Some(unsafe { syscalls::memop(9, i) as *const u8 })
    } else {
        None
    }
}

// It is safe to return a 'static immutable slice, as the Tock kernel doesn't change the layout of
// flash regions during the application's lifetime.
pub fn get_flash_region(i: usize) -> Option<&'static [u8]> {
    if i < get_flash_regions_count() {
        let start = unsafe { syscalls::memop(8, i) as *const u8 };
        let end = unsafe { syscalls::memop(9, i) as *const u8 };
        // This assumes that the kernel sends consistent results, i.e. start <= end.
        let len = unsafe { end.offset_from(start) } as usize;
        Some(unsafe { slice::from_raw_parts(start, len) })
    } else {
        None
    }
}

// Setting the stack_top and heap_start addresses are marked as unsafe as they should only be called
// by the entry point to setup the allocator. Updating these values afterwards can lead to incorrect
// debug output from the kernel.
//
// Alternate allocator implementations may still find this useful in the future.
pub unsafe fn set_stack_top(ptr: *const u8) {
    let _ = syscalls::memop(10, ptr as usize);
}

pub unsafe fn set_heap_start(ptr: *const u8) {
    let _ = syscalls::memop(11, ptr as usize);
}
<|endoftext|>


<commit_before>use iron::{Handler, Response, Request, IronResult, IronError, Url, Error};
use typemap::Assoc;
use trie::Trie;

/// Exposes the original, unmodified path to be stored in `Request::extensions`.
pub struct OriginalUrl;
impl Assoc<Url> for OriginalUrl {}

/// `Mount` is a simple mounting middleware.
///
/// Mounting allows you to install a handler on a route and have it receive requests as if they
/// are relative to that route. For example, a handler mounted on `/foo/` will receive
/// requests like `/foo/bar` as if they are just `/bar`. Iron's mounting middleware allows
/// you to specify multiple mountings using one middleware instance. Requests that pass through
/// the mounting middleware are passed along to the mounted handler that best matches the request's
/// path. `Request::url` is modified so that requests appear to be relative to the mounted handler's route.
///
/// Mounted handlers may also access the *original* URL by requesting the `OriginalUrl` key
/// from `Request::extensions`.
pub struct Mount {
    inner: Trie<String, Match>
}

struct Match {
    handler: Box<Handler + Send + Sync>,
    length: uint
}

/// The error returned by `Mount` when a request doesn't match any mounted handlers.
#[deriving(Show)]
pub struct NoMatch;

impl Error for NoMatch {
    fn name(&self) -> &'static str { "No Match" }
}

impl Mount {
    /// Creates a new instance of `Mount`.
    pub fn new() -> Mount {
        Mount {
            inner: Trie::new()
        }
    }

    /// Mounts a given `Handler` onto a route.
    ///
    /// This method may be called multiple times with different routes.
    /// For a given request, the *most specific* handler will be selected.
    ///
    /// Existing handlers on the same route will be overwritten.
    pub fn mount<H: Handler>(&mut self, route: &str, handler: H) -> &mut Mount {
        // Parse the route into a list of strings. The unwrap is safe because strs are UTF-8.
        let key: Vec<String> = Path::new(route).str_components().map(|s| s.unwrap().to_string()).collect();

        // Insert a match struct into the trie.
        self.inner.insert(key.as_slice(), Match {
            handler: box handler as Box<Handler + Send + Sync>,
            length: key.len()
        });
        self
    }
}

impl Handler for Mount {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        // Find the matching handler.
        let matched = {
            // Extract the request path.
            let path = req.url.path.as_slice();

            // If present, remove the trailing empty string (which represents a trailing slash).
            // If it isn't removed the path will never match anything, because
            // Path::str_components ignores trailing slashes and will never create routes
            // ending in "".
            let key = match path.last() {
                Some(s) if s.is_empty() => path.slice_to(path.len() - 1),
                _ => path
            };

            // Search the Trie for the nearest most specific match.
            match self.inner.find_ancestor(key) {
                Some(matched) => matched,
                None => return Err(box NoMatch as IronError)
            }
        };

        // We have a match, so fire off the child.
        // If another mount middleware hasn't already, insert the unmodified url
        // into the extensions as the "original url".
        let is_outer_mount = !req.extensions.contains::<OriginalUrl, Url>();
        if is_outer_mount {
            req.extensions.insert::<OriginalUrl, Url>(req.url.clone());
        }

        // Remove the prefix from the request's path before passing it to the mounted handler.
        // If the prefix is entirely removed and no trailing slash was present, the new path
        // will be the empty list. For the purposes of redirection, conveying that the path
        // did not include a trailing slash is more important than providing a non-empty list.
        req.url.path = req.url.path.as_slice().slice_from(matched.length).to_vec();

        let res = matched.handler.call(req);

        // Reverse the URL munging, for future middleware.
        req.url = match req.extensions.find::<OriginalUrl, Url>() {
            Some(original) => original.clone(),
            None => panic!("OriginalUrl unexpectedly removed from req.extensions.")
        };

        // If this mount middleware is the outermost mount middleware,
        // remove the original url from the extensions map to prevent leakage.
        if is_outer_mount {
            req.extensions.remove::<OriginalUrl, Url>();
        }

        res
    }
}

<commit_msg>(fix) Fix for typemap changes.<commit_after>use iron::{Handler, Response, Request, IronResult, IronError, Url, Error};
use typemap::Assoc;
use trie::Trie;

/// Exposes the original, unmodified path to be stored in `Request::extensions`.
pub struct OriginalUrl;
impl Assoc<Url> for OriginalUrl {}

/// `Mount` is a simple mounting middleware.
///
/// Mounting allows you to install a handler on a route and have it receive requests as if they
/// are relative to that route. For example, a handler mounted on `/foo/` will receive
/// requests like `/foo/bar` as if they are just `/bar`. Iron's mounting middleware allows
/// you to specify multiple mountings using one middleware instance. Requests that pass through
/// the mounting middleware are passed along to the mounted handler that best matches the request's
/// path. `Request::url` is modified so that requests appear to be relative to the mounted handler's route.
///
/// Mounted handlers may also access the *original* URL by requesting the `OriginalUrl` key
/// from `Request::extensions`.
pub struct Mount {
    inner: Trie<String, Match>
}

struct Match {
    handler: Box<Handler + Send + Sync>,
    length: uint
}

/// The error returned by `Mount` when a request doesn't match any mounted handlers.
#[deriving(Show)]
pub struct NoMatch;

impl Error for NoMatch {
    fn name(&self) -> &'static str { "No Match" }
}

impl Mount {
    /// Creates a new instance of `Mount`.
    pub fn new() -> Mount {
        Mount {
            inner: Trie::new()
        }
    }

    /// Mounts a given `Handler` onto a route.
    ///
    /// This method may be called multiple times with different routes.
    /// For a given request, the *most specific* handler will be selected.
    ///
    /// Existing handlers on the same route will be overwritten.
    pub fn mount<H: Handler>(&mut self, route: &str, handler: H) -> &mut Mount {
        // Parse the route into a list of strings. The unwrap is safe because strs are UTF-8.
        let key: Vec<String> = Path::new(route).str_components().map(|s| s.unwrap().to_string()).collect();

        // Insert a match struct into the trie.
        self.inner.insert(key.as_slice(), Match {
            handler: box handler as Box<Handler + Send + Sync>,
            length: key.len()
        });
        self
    }
}

impl Handler for Mount {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        // Find the matching handler.
        let matched = {
            // Extract the request path.
            let path = req.url.path.as_slice();

            // If present, remove the trailing empty string (which represents a trailing slash).
            // If it isn't removed the path will never match anything, because
            // Path::str_components ignores trailing slashes and will never create routes
            // ending in "".
            let key = match path.last() {
                Some(s) if s.is_empty() => path.slice_to(path.len() - 1),
                _ => path
            };

            // Search the Trie for the nearest most specific match.
            match self.inner.find_ancestor(key) {
                Some(matched) => matched,
                None => return Err(box NoMatch as IronError)
            }
        };

        // We have a match, so fire off the child.
        // If another mount middleware hasn't already, insert the unmodified url
        // into the extensions as the "original url".
        let is_outer_mount = !req.extensions.contains::<OriginalUrl, Url>();
        if is_outer_mount {
            req.extensions.insert::<OriginalUrl, Url>(req.url.clone());
        }

        // Remove the prefix from the request's path before passing it to the mounted handler.
        // If the prefix is entirely removed and no trailing slash was present, the new path
        // will be the empty list. For the purposes of redirection, conveying that the path
        // did not include a trailing slash is more important than providing a non-empty list.
        req.url.path = req.url.path.as_slice().slice_from(matched.length).to_vec();

        let res = matched.handler.call(req);

        // Reverse the URL munging, for future middleware.
        req.url = match req.extensions.get::<OriginalUrl, Url>() {
            Some(original) => original.clone(),
            None => panic!("OriginalUrl unexpectedly removed from req.extensions.")
        };

        // If this mount middleware is the outermost mount middleware,
        // remove the original url from the extensions map to prevent leakage.
        if is_outer_mount {
            req.extensions.remove::<OriginalUrl, Url>();
        }

        res
    }
}

<|endoftext|>


<commit_before>extern crate revord;
use std::cmp::Ordering;
use self::revord::RevOrd;
use std::collections::BinaryHeap;

fn bucket_distance(fi: f64, hi: f64, delta: i32, W: f64) -> f64 {
    if delta == -1 {
        W*(fi - hi)
    } else if delta == 1 {
        W - W*(fi - hi)
    } else {
        0 as f64
    }
}
fn compute_sorted_i_delta<T>(q: &[T], f_sig: &[f64], h_sig: &[f64], W: f64) -> Vec<(usize, i32)> {
    let mut intermediate_vec: Vec<((usize,i32), f64)> = f_sig.iter().zip(h_sig.iter()).enumerate().flat_map(|(i, (fi, hi))| {
        vec![((i, 1), bucket_distance(*fi, *hi, 1, W)),
         ((i, -1), bucket_distance(*fi, *hi, -1, W))].into_iter()
    }).collect();
    intermediate_vec.sort_by(|a, b| {
        if a.1 > b.1 {
            Ordering::Greater
        } else if a.1 < b.1 {
            Ordering::Less
        } else {
            Ordering::Equal
        }
    });
    intermediate_vec.iter().map(|a| {a.0}).collect()
}
#[test]
fn sorted_delta_test() {
    let test_q = vec![1.0,2.0,3.0,4.0,5.0];
    let f_sig = vec![1.5,1.2,2.2];
    let h_sig = vec![1.0,1.0,2.0];
    let W = 10.0;
    compute_sorted_i_delta(&test_q, &f_sig, &h_sig, W);
}
fn score_set(perturbation_set: &[usize], square_zj_list: &[f64]) -> f64 {
    perturbation_set.iter().map(|ind| {square_zj_list[*ind]}).sum()
}

#[derive(PartialEq)]
struct PerturbationSet<'a> {
    data: Vec<usize>,
    zj_list: &'a Vec<f64>
}

fn gen_perturbation_sets<'a>(zj_l: &'a Vec<f64>) -> PerturbationIterator<'a> {
    let mut new_heap = BinaryHeap::new();
    let zero_vec = vec![0];
    let a0 = PerturbationSet {
        data: zero_vec,
        zj_list: zj_l
    };
    new_heap.push(RevOrd(a0));
    PerturbationIterator {
        heap: new_heap,
        zj_list: zj_l
    }
}
struct PerturbationIterator<'a> {
    heap: BinaryHeap<RevOrd<PerturbationSet<'a>>>,
    zj_list: &'a Vec<f64>
}

impl<'a> Iterator for PerturbationIterator<'a> {
    type Item = PerturbationSet<'a>;
    fn next(&mut self) -> Option<PerturbationSet<'a>> {
        loop {
            match self.heap.pop() {
                Some(revord_val) => {
                    let a_i = revord_val.0;
                    let a_s = a_i.shift();
                    //self.heap.push(RevOrd(a_s));
                    let a_e = a_i.expand();
                    //self.heap.push(RevOrd(a_e));

                    if a_i.valid() {
                        return Some(a_i);
                    }
                },
                None => return None
            };
        }
    }
}

impl<'a> Eq for PerturbationSet<'a> {}

impl<'a> Ord for PerturbationSet<'a> {
    fn cmp(&self, other: &PerturbationSet) -> Ordering {
        let self_score = score_set(&(self.data), self.zj_list);
        let other_score = score_set(&(other.data), other.zj_list);
        if (self_score - other_score) <= 1e-6 {
            Ordering::Equal
        } else if self_score > other_score {
            Ordering::Greater
        } else {
            Ordering::Less
        }
    }
}

impl<'a> PartialOrd for PerturbationSet<'a> {
    fn partial_cmp(&self, other: &PerturbationSet) -> Option<Ordering> {
        let self_score = score_set(&(self.data), self.zj_list);
        let other_score = score_set(&(other.data), other.zj_list);
        self_score.partial_cmp(&other_score)
    }
}
impl<'a> PerturbationSet<'a> {
    pub fn shift<'b>(&'b self) -> PerturbationSet<'a> {
        let mut new_data = Vec::new();
        let max_val = self.data.iter().max().unwrap();
        let newlist = self.zj_list;
        for &x in self.data.iter() {
            let y = x;
            if y == *max_val {
                new_data.push(y+1);
            } else {
                new_data.push(y);
            }
        }
        PerturbationSet {
            data: new_data,
            zj_list: newlist
        }
    }
    pub fn valid(&self) -> bool {
        unimplemented!();
    }
    pub fn expand<'b>(&'b self) -> PerturbationSet<'a> {
        let mut new_data = Vec::new();
        let max_val = self.data.iter().max().unwrap();
        for &x in self.data.iter() {
            new_data.push(x);
        }
        new_data.push(*max_val + 1);
        PerturbationSet {
            data: new_data,
            zj_list: self.zj_list
        }
    }
}
<commit_msg>basic tests working, some linting<commit_after>extern crate revord;
use std::cmp::Ordering;
use self::revord::RevOrd;
use std::collections::BinaryHeap;

fn bucket_distance(fi: f64, hi: f64, delta: i32, W: f64) -> f64 {
    if delta == -1 {
        W*(fi - hi)
    } else if delta == 1 {
        W - W*(fi - hi)
    } else {
        0 as f64
    }
}
fn compute_sorted_i_delta<T>(q: &[T], f_sig: &[f64], h_sig: &[f64], W: f64) -> Vec<(usize, i32)> {
    let mut intermediate_vec: Vec<((usize,i32), f64)> = f_sig.iter().zip(h_sig.iter()).enumerate().flat_map(|(i, (fi, hi))| {
        vec![((i, 1), bucket_distance(*fi, *hi, 1, W)),
         ((i, -1), bucket_distance(*fi, *hi, -1, W))].into_iter()
    }).collect();
    intermediate_vec.sort_by(|a, b| {
        if a.1 > b.1 {
            Ordering::Greater
        } else if a.1 < b.1 {
            Ordering::Less
        } else {
            Ordering::Equal
        }
    });
    intermediate_vec.iter().map(|a| {a.0}).collect()
}
#[test]
fn sorted_delta_test() {
    let test_q = vec![1.0,2.0,3.0,4.0,5.0];
    let f_sig = vec![1.5,1.2,2.2];
    let h_sig = vec![1.0,1.0,2.0];
    let W = 10.0;
    compute_sorted_i_delta(&test_q, &f_sig, &h_sig, W);
}
fn score_set(perturbation_set: &[usize], square_zj_list: &[f64]) -> f64 {
    perturbation_set.iter().map(|ind| {square_zj_list[*ind]}).sum()
}

#[derive(PartialEq)]
struct PerturbationSet<'a> {
    data: Vec<usize>,
    zj_list: &'a [f64]
}

fn gen_perturbation_sets<'a>(zj_l: &'a [f64]) -> PerturbationIterator<'a> {
    let mut new_heap = BinaryHeap::new();
    let zero_vec = vec![0];
    let a0 = PerturbationSet {
        data: zero_vec,
        zj_list: zj_l
    };
    new_heap.push(RevOrd(a0));
    PerturbationIterator {
        heap: new_heap,
        zj_list: zj_l
    }
}
struct PerturbationIterator<'a> {
    heap: BinaryHeap<RevOrd<PerturbationSet<'a>>>,
    zj_list: &'a [f64]
}

#[test]
fn test_perturbation_iterator() {
    let zjl = vec![1.0,2.0,3.0,4.0];
    let ii = gen_perturbation_sets(&zjl);
    let z: Vec<_> = ii.take(3).collect();
}
impl<'a> Iterator for PerturbationIterator<'a> {
    type Item = PerturbationSet<'a>;
    fn next(&mut self) -> Option<PerturbationSet<'a>> {
        loop {
            match self.heap.pop() {
                Some(revord_val) => {
                    let a_i = revord_val.0;
                    let a_s = a_i.shift();
                    self.heap.push(RevOrd(a_s));
                    let a_e = a_i.expand();
                    self.heap.push(RevOrd(a_e));

                    if a_i.valid() {
                        return Some(a_i);
                    }
                },
                None => return None
            };
        }
    }
}

impl<'a> Eq for PerturbationSet<'a> {}

impl<'a> Ord for PerturbationSet<'a> {
    fn cmp(&self, other: &PerturbationSet) -> Ordering {
        let self_score = score_set(&(self.data), self.zj_list);
        let other_score = score_set(&(other.data), other.zj_list);
        if (self_score - other_score) <= 1e-6 {
            Ordering::Equal
        } else if self_score > other_score {
            Ordering::Greater
        } else {
            Ordering::Less
        }
    }
}

impl<'a> PartialOrd for PerturbationSet<'a> {
    fn partial_cmp(&self, other: &PerturbationSet) -> Option<Ordering> {
        let self_score = score_set(&(self.data), self.zj_list);
        let other_score = score_set(&(other.data), other.zj_list);
        self_score.partial_cmp(&other_score)
    }
}
impl<'a> PerturbationSet<'a> {
    pub fn shift<'b>(&'b self) -> PerturbationSet<'a> {
        let mut new_data = Vec::new();
        let max_val = self.data.iter().max().unwrap();
        let newlist = self.zj_list;
        for &x in &self.data {
            let y = x;
            if y == *max_val {
                new_data.push(y+1);
            } else {
                new_data.push(y);
            }
        }
        PerturbationSet {
            data: new_data,
            zj_list: newlist
        }
    }
    pub fn valid(&self) -> bool {
        let max_m = 10; //DUMMY!
        for &val in &self.data {
            let other_should_be_missing = 2 * max_m + 1 - val;
            if let Some(_) = self.data.iter().position(|&y| { y == other_should_be_missing}) {
                return false;
            }
        }
        true
    }
    pub fn expand<'b>(&'b self) -> PerturbationSet<'a> {
        let mut new_data = Vec::new();
        let max_val = self.data.iter().max().unwrap();
        for &x in &self.data {
            new_data.push(x);
        }
        new_data.push(*max_val + 1);
        PerturbationSet {
            data: new_data,
            zj_list: self.zj_list
        }
    }
}
<|endoftext|>


<commit_before>//! `feature = "trace"` Tracing and profiling functions. Error and warning log.

use std::ffi::{CStr, CString};
use std::mem;
use std::os::raw::{c_char, c_int, c_void};
use std::panic::catch_unwind;
use std::ptr;
use std::time::Duration;

use super::ffi;
use crate::error::error_from_sqlite_code;
use crate::{Connection, Result};

/// `feature = "trace"` Set up the process-wide SQLite error logging callback.
///
/// # Safety
///
/// This function is marked unsafe for two reasons:
///
/// * The function is not threadsafe. No other SQLite calls may be made while
///   `config_log` is running, and multiple threads may not call `config_log`
///   simultaneously.
/// * The provided `callback` itself function has two requirements:
///     * It must not invoke any SQLite calls.
///     * It must be threadsafe if SQLite is used in a multithreaded way.
///
/// cf [The Error And Warning Log](http://sqlite.org/errlog.html).
pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> Result<()> {
    extern "C" fn log_callback(p_arg: *mut c_void, err: c_int, msg: *const c_char) {
        let c_slice = unsafe { CStr::from_ptr(msg).to_bytes() };
        let callback: fn(c_int, &str) = unsafe { mem::transmute(p_arg) };

        let s = String::from_utf8_lossy(c_slice);
        let _ = catch_unwind(|| callback(err, &s));
    }

    let rc = match callback {
        Some(f) => {
            let p_arg: *mut c_void = mem::transmute(f);
            ffi::sqlite3_config(
                ffi::SQLITE_CONFIG_LOG,
                log_callback as extern "C" fn(_, _, _),
                p_arg,
            )
        }
        None => {
            let nullptr: *mut c_void = ptr::null_mut();
            ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, nullptr, nullptr)
        }
    };

    if rc == ffi::SQLITE_OK {
        Ok(())
    } else {
        Err(error_from_sqlite_code(rc, None))
    }
}

/// `feature = "trace"` Write a message into the error log established by
/// `config_log`.
pub fn log(err_code: c_int, msg: &str) {
    let msg = CString::new(msg).expect("SQLite log messages cannot contain embedded zeroes");
    unsafe {
        ffi::sqlite3_log(err_code, msg.as_ptr());
    }
}

impl Connection {
    /// `feature = "trace"` Register or clear a callback function that can be
    /// used for tracing the execution of SQL statements.
    ///
    /// Prepared statement placeholders are replaced/logged with their assigned
    /// values. There can only be a single tracer defined for each database
    /// connection. Setting a new tracer clears the old one.
    pub fn trace(&mut self, trace_fn: Option<fn(&str)>) {
        unsafe extern "C" fn trace_callback(p_arg: *mut c_void, z_sql: *const c_char) {
            let trace_fn: fn(&str) = mem::transmute(p_arg);
            let c_slice = CStr::from_ptr(z_sql).to_bytes();
            let s = String::from_utf8_lossy(c_slice);
            let _ = catch_unwind(|| trace_fn(&s));
        }

        let c = self.db.borrow_mut();
        match trace_fn {
            Some(f) => unsafe {
                ffi::sqlite3_trace(c.db(), Some(trace_callback), mem::transmute(f));
            },
            None => unsafe {
                ffi::sqlite3_trace(c.db(), None, ptr::null_mut());
            },
        }
    }

    /// `feature = "trace"` Register or clear a callback function that can be
    /// used for profiling the execution of SQL statements.
    ///
    /// There can only be a single profiler defined for each database
    /// connection. Setting a new profiler clears the old one.
    pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) {
        unsafe extern "C" fn profile_callback(
            p_arg: *mut c_void,
            z_sql: *const c_char,
            nanoseconds: u64,
        ) {
            let profile_fn: fn(&str, Duration) = mem::transmute(p_arg);
            let c_slice = CStr::from_ptr(z_sql).to_bytes();
            let s = String::from_utf8_lossy(c_slice);
            const NANOS_PER_SEC: u64 = 1_000_000_000;

            let duration = Duration::new(
                nanoseconds / NANOS_PER_SEC,
                (nanoseconds % NANOS_PER_SEC) as u32,
            );
            let _ = catch_unwind(|| profile_fn(&s, duration));
        }

        let c = self.db.borrow_mut();
        match profile_fn {
            Some(f) => unsafe {
                ffi::sqlite3_profile(c.db(), Some(profile_callback), mem::transmute(f))
            },
            None => unsafe { ffi::sqlite3_profile(c.db(), None, ptr::null_mut()) },
        };
    }
}

#[cfg(test)]
mod test {
    use lazy_static::lazy_static;
    use std::sync::Mutex;
    use std::time::Duration;

    use crate::Connection;

    #[test]
    fn test_trace() {
        lazy_static! {
            static ref TRACED_STMTS: Mutex<Vec<String>> = Mutex::new(Vec::new());
        }
        fn tracer(s: &str) {
            let mut traced_stmts = TRACED_STMTS.lock().unwrap();
            traced_stmts.push(s.to_owned());
        }

        let mut db = Connection::open_in_memory().unwrap();
        db.trace(Some(tracer));
        {
            let _ = db.query_row("SELECT ?", &[1i32], |_| Ok(()));
            let _ = db.query_row("SELECT ?", &["hello"], |_| Ok(()));
        }
        db.trace(None);
        {
            let _ = db.query_row("SELECT ?", &[2i32], |_| Ok(()));
            let _ = db.query_row("SELECT ?", &["goodbye"], |_| Ok(()));
        }

        let traced_stmts = TRACED_STMTS.lock().unwrap();
        assert_eq!(traced_stmts.len(), 2);
        assert_eq!(traced_stmts[0], "SELECT 1");
        assert_eq!(traced_stmts[1], "SELECT 'hello'");
    }

    #[test]
    fn test_profile() {
        lazy_static! {
            static ref PROFILED: Mutex<Vec<(String, Duration)>> = Mutex::new(Vec::new());
        }
        fn profiler(s: &str, d: Duration) {
            let mut profiled = PROFILED.lock().unwrap();
            profiled.push((s.to_owned(), d));
        }

        let mut db = Connection::open_in_memory().unwrap();
        db.profile(Some(profiler));
        db.execute_batch("PRAGMA application_id = 1").unwrap();
        db.profile(None);
        db.execute_batch("PRAGMA application_id = 2").unwrap();

        let profiled = PROFILED.lock().unwrap();
        assert_eq!(profiled.len(), 1);
        assert_eq!(profiled[0].0, "PRAGMA application_id = 1");
    }
}
<commit_msg>Fix format string error in rusqlite::trace::log<commit_after>//! `feature = "trace"` Tracing and profiling functions. Error and warning log.

use std::ffi::{CStr, CString};
use std::mem;
use std::os::raw::{c_char, c_int, c_void};
use std::panic::catch_unwind;
use std::ptr;
use std::time::Duration;

use super::ffi;
use crate::error::error_from_sqlite_code;
use crate::{Connection, Result};

/// `feature = "trace"` Set up the process-wide SQLite error logging callback.
///
/// # Safety
///
/// This function is marked unsafe for two reasons:
///
/// * The function is not threadsafe. No other SQLite calls may be made while
///   `config_log` is running, and multiple threads may not call `config_log`
///   simultaneously.
/// * The provided `callback` itself function has two requirements:
///     * It must not invoke any SQLite calls.
///     * It must be threadsafe if SQLite is used in a multithreaded way.
///
/// cf [The Error And Warning Log](http://sqlite.org/errlog.html).
pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> Result<()> {
    extern "C" fn log_callback(p_arg: *mut c_void, err: c_int, msg: *const c_char) {
        let c_slice = unsafe { CStr::from_ptr(msg).to_bytes() };
        let callback: fn(c_int, &str) = unsafe { mem::transmute(p_arg) };

        let s = String::from_utf8_lossy(c_slice);
        let _ = catch_unwind(|| callback(err, &s));
    }

    let rc = match callback {
        Some(f) => {
            let p_arg: *mut c_void = mem::transmute(f);
            ffi::sqlite3_config(
                ffi::SQLITE_CONFIG_LOG,
                log_callback as extern "C" fn(_, _, _),
                p_arg,
            )
        }
        None => {
            let nullptr: *mut c_void = ptr::null_mut();
            ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, nullptr, nullptr)
        }
    };

    if rc == ffi::SQLITE_OK {
        Ok(())
    } else {
        Err(error_from_sqlite_code(rc, None))
    }
}

/// `feature = "trace"` Write a message into the error log established by
/// `config_log`.
pub fn log(err_code: c_int, msg: &str) {
    let msg = CString::new(msg).expect("SQLite log messages cannot contain embedded zeroes");
    unsafe {
        ffi::sqlite3_log(err_code, b"%s\0" as *const _ as *const c_char, msg.as_ptr());
    }
}

impl Connection {
    /// `feature = "trace"` Register or clear a callback function that can be
    /// used for tracing the execution of SQL statements.
    ///
    /// Prepared statement placeholders are replaced/logged with their assigned
    /// values. There can only be a single tracer defined for each database
    /// connection. Setting a new tracer clears the old one.
    pub fn trace(&mut self, trace_fn: Option<fn(&str)>) {
        unsafe extern "C" fn trace_callback(p_arg: *mut c_void, z_sql: *const c_char) {
            let trace_fn: fn(&str) = mem::transmute(p_arg);
            let c_slice = CStr::from_ptr(z_sql).to_bytes();
            let s = String::from_utf8_lossy(c_slice);
            let _ = catch_unwind(|| trace_fn(&s));
        }

        let c = self.db.borrow_mut();
        match trace_fn {
            Some(f) => unsafe {
                ffi::sqlite3_trace(c.db(), Some(trace_callback), mem::transmute(f));
            },
            None => unsafe {
                ffi::sqlite3_trace(c.db(), None, ptr::null_mut());
            },
        }
    }

    /// `feature = "trace"` Register or clear a callback function that can be
    /// used for profiling the execution of SQL statements.
    ///
    /// There can only be a single profiler defined for each database
    /// connection. Setting a new profiler clears the old one.
    pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) {
        unsafe extern "C" fn profile_callback(
            p_arg: *mut c_void,
            z_sql: *const c_char,
            nanoseconds: u64,
        ) {
            let profile_fn: fn(&str, Duration) = mem::transmute(p_arg);
            let c_slice = CStr::from_ptr(z_sql).to_bytes();
            let s = String::from_utf8_lossy(c_slice);
            const NANOS_PER_SEC: u64 = 1_000_000_000;

            let duration = Duration::new(
                nanoseconds / NANOS_PER_SEC,
                (nanoseconds % NANOS_PER_SEC) as u32,
            );
            let _ = catch_unwind(|| profile_fn(&s, duration));
        }

        let c = self.db.borrow_mut();
        match profile_fn {
            Some(f) => unsafe {
                ffi::sqlite3_profile(c.db(), Some(profile_callback), mem::transmute(f))
            },
            None => unsafe { ffi::sqlite3_profile(c.db(), None, ptr::null_mut()) },
        };
    }
}

#[cfg(test)]
mod test {
    use lazy_static::lazy_static;
    use std::sync::Mutex;
    use std::time::Duration;

    use crate::Connection;

    #[test]
    fn test_trace() {
        lazy_static! {
            static ref TRACED_STMTS: Mutex<Vec<String>> = Mutex::new(Vec::new());
        }
        fn tracer(s: &str) {
            let mut traced_stmts = TRACED_STMTS.lock().unwrap();
            traced_stmts.push(s.to_owned());
        }

        let mut db = Connection::open_in_memory().unwrap();
        db.trace(Some(tracer));
        {
            let _ = db.query_row("SELECT ?", &[1i32], |_| Ok(()));
            let _ = db.query_row("SELECT ?", &["hello"], |_| Ok(()));
        }
        db.trace(None);
        {
            let _ = db.query_row("SELECT ?", &[2i32], |_| Ok(()));
            let _ = db.query_row("SELECT ?", &["goodbye"], |_| Ok(()));
        }

        let traced_stmts = TRACED_STMTS.lock().unwrap();
        assert_eq!(traced_stmts.len(), 2);
        assert_eq!(traced_stmts[0], "SELECT 1");
        assert_eq!(traced_stmts[1], "SELECT 'hello'");
    }

    #[test]
    fn test_profile() {
        lazy_static! {
            static ref PROFILED: Mutex<Vec<(String, Duration)>> = Mutex::new(Vec::new());
        }
        fn profiler(s: &str, d: Duration) {
            let mut profiled = PROFILED.lock().unwrap();
            profiled.push((s.to_owned(), d));
        }

        let mut db = Connection::open_in_memory().unwrap();
        db.profile(Some(profiler));
        db.execute_batch("PRAGMA application_id = 1").unwrap();
        db.profile(None);
        db.execute_batch("PRAGMA application_id = 2").unwrap();

        let profiled = PROFILED.lock().unwrap();
        assert_eq!(profiled.len(), 1);
        assert_eq!(profiled[0].0, "PRAGMA application_id = 1");
    }
}
<|endoftext|>


<commit_before>extern crate ruster_unsafe;
extern crate libc;

use super::{ NifEnv, NifTerm, NifError };

pub trait NifEncoder {
    fn encode<'a>(&self, env: &'a NifEnv) -> NifTerm<'a>;
}
pub trait NifDecoder<'a>: Sized+'a {
    fn decode(term: NifTerm<'a>, env: &NifEnv) -> Result<Self, NifError>;
}

macro_rules! impl_number_transcoder {
    ($typ:ty, $encode_fun:ident, $decode_fun:ident) => {
        impl NifEncoder for $typ {
            fn encode<'a>(&self, env: &'a NifEnv) -> NifTerm<'a> {
                #![allow(unused_unsafe)]
                NifTerm::new(env, unsafe { ruster_unsafe::$encode_fun(env.env, *self) })
            }
        }
        impl<'a> NifDecoder<'a> for $typ {
            fn decode(term: NifTerm, env: &NifEnv) -> Result<$typ, NifError> {
                #![allow(unused_unsafe)]
                let mut res: $typ = Default::default();
                if unsafe { ruster_unsafe::$decode_fun(env.env, term.term, (&mut res) as *mut $typ) } == 0 {
                    return Err(NifError::BadArg);
                }
                Ok(res)
            }
        }
    }
}

impl_number_transcoder!(libc::c_int, enif_make_int, enif_get_int);
impl_number_transcoder!(libc::c_uint, enif_make_uint, enif_get_uint);
impl_number_transcoder!(u64, enif_make_uint64, enif_get_uint64);
impl_number_transcoder!(i64, enif_make_int64, enif_get_int64);
impl_number_transcoder!(libc::c_double, enif_make_double, enif_get_double);

use super::atom::{ get_atom };
impl NifEncoder for bool {
    fn encode<'a>(&self, env: &'a NifEnv) -> NifTerm<'a> {
        if *self {
            get_atom("true").unwrap().to_term(env)
        } else {
            get_atom("false").unwrap().to_term(env)
        }
    }
}
impl<'a> NifDecoder<'a> for bool {
    fn decode(term: NifTerm<'a>, env: &NifEnv) -> Result<bool, NifError> {
        Ok(super::atom::is_term_truthy(term, env))
    }
}

impl<'a> NifDecoder<'a> for String {
    fn decode(term: NifTerm<'a>, env: &NifEnv) -> Result<Self, NifError> {
        let string: &str = try!(NifDecoder::decode(term, env));
        Ok(string.to_string())
    }
}
impl<'a> NifDecoder<'a> for &'a str {
    fn decode(term: NifTerm<'a>, env: &NifEnv) -> Result<Self, NifError> {
        let binary = try!(::binary::NifBinary::from_term(term, env));
        match ::std::str::from_utf8(binary.as_slice()) {
            Ok(string) => Ok(string),
            Err(_) => Err(NifError::BadArg),
        }
    }
}

use std::io::Write;

impl NifEncoder for str {
    fn encode<'b>(&self, env: &'b NifEnv) -> NifTerm<'b> {
        let str_len = self.len();
        let mut bin = match ::binary::OwnedNifBinary::alloc(str_len) {
            Some(bin) => bin,
            None => panic!("binary term alloc failed"),
        };
        bin.as_mut_slice().write(self.as_bytes()).expect("memory copy of string failed");
        bin.release(env).get_term(env)
    }
}

impl<'a> NifEncoder for NifTerm<'a> {
    fn encode<'b>(&self, env: &'b NifEnv) -> NifTerm<'b> {
        NifTerm::new(env, self.as_c_arg())
    }
}
impl<'a> NifDecoder<'a> for NifTerm<'a> {
    fn decode(term: NifTerm<'a>, _env: &NifEnv) -> Result<Self, NifError> {
        Ok(term)
    }
}
<commit_msg>Pin c types to rust types in number decoder, and implement casting decoders for all numeric types. This might create problems for different architechtures, will fix later if there is a better solution.<commit_after>extern crate ruster_unsafe;
extern crate libc;

use super::{ NifEnv, NifTerm, NifError };

pub trait NifEncoder {
    fn encode<'a>(&self, env: &'a NifEnv) -> NifTerm<'a>;
}
pub trait NifDecoder<'a>: Sized+'a {
    fn decode(term: NifTerm<'a>, env: &NifEnv) -> Result<Self, NifError>;
}

macro_rules! impl_number_transcoder {
    ($dec_type:ty, $nif_type:ty, $encode_fun:ident, $decode_fun:ident) => {
        impl NifEncoder for $dec_type {
            fn encode<'a>(&self, env: &'a NifEnv) -> NifTerm<'a> {
                #![allow(unused_unsafe)]
                NifTerm::new(env, unsafe { ruster_unsafe::$encode_fun(env.env, *self as $nif_type) })
            }
        }
        impl<'a> NifDecoder<'a> for $dec_type {
            fn decode(term: NifTerm, env: &NifEnv) -> Result<$dec_type, NifError> {
                #![allow(unused_unsafe)]
                let mut res: $nif_type = Default::default();
                if unsafe { ruster_unsafe::$decode_fun(env.env, term.term, (&mut res) as *mut $nif_type) } == 0 {
                    return Err(NifError::BadArg);
                }
                Ok(res as $dec_type)
            }
        }
    }
}

// Base number types
impl_number_transcoder!(i32, i32, enif_make_int, enif_get_int);
impl_number_transcoder!(u32, u32, enif_make_uint, enif_get_uint);
impl_number_transcoder!(i64, i64, enif_make_int64, enif_get_int64);
impl_number_transcoder!(u64, u64, enif_make_uint64, enif_get_uint64);
impl_number_transcoder!(f64, f64, enif_make_double, enif_get_double);

// Casted number types
impl_number_transcoder!(i8, i32, enif_make_int, enif_get_int);
impl_number_transcoder!(u8, u32, enif_make_uint, enif_get_uint);
impl_number_transcoder!(i16, i32, enif_make_int, enif_get_int);
impl_number_transcoder!(u16, u32, enif_make_uint, enif_get_uint);
impl_number_transcoder!(f32, f64, enif_make_double, enif_get_double);

use super::atom::{ get_atom };
impl NifEncoder for bool {
    fn encode<'a>(&self, env: &'a NifEnv) -> NifTerm<'a> {
        if *self {
            get_atom("true").unwrap().to_term(env)
        } else {
            get_atom("false").unwrap().to_term(env)
        }
    }
}
impl<'a> NifDecoder<'a> for bool {
    fn decode(term: NifTerm<'a>, env: &NifEnv) -> Result<bool, NifError> {
        Ok(super::atom::is_term_truthy(term, env))
    }
}

impl<'a> NifDecoder<'a> for String {
    fn decode(term: NifTerm<'a>, env: &NifEnv) -> Result<Self, NifError> {
        let string: &str = try!(NifDecoder::decode(term, env));
        Ok(string.to_string())
    }
}
impl<'a> NifDecoder<'a> for &'a str {
    fn decode(term: NifTerm<'a>, env: &NifEnv) -> Result<Self, NifError> {
        let binary = try!(::binary::NifBinary::from_term(term, env));
        match ::std::str::from_utf8(binary.as_slice()) {
            Ok(string) => Ok(string),
            Err(_) => Err(NifError::BadArg),
        }
    }
}

use std::io::Write;

impl NifEncoder for str {
    fn encode<'b>(&self, env: &'b NifEnv) -> NifTerm<'b> {
        let str_len = self.len();
        let mut bin = match ::binary::OwnedNifBinary::alloc(str_len) {
            Some(bin) => bin,
            None => panic!("binary term alloc failed"),
        };
        bin.as_mut_slice().write(self.as_bytes()).expect("memory copy of string failed");
        bin.release(env).get_term(env)
    }
}

impl<'a> NifEncoder for NifTerm<'a> {
    fn encode<'b>(&self, env: &'b NifEnv) -> NifTerm<'b> {
        NifTerm::new(env, self.as_c_arg())
    }
}
impl<'a> NifDecoder<'a> for NifTerm<'a> {
    fn decode(term: NifTerm<'a>, _env: &NifEnv) -> Result<Self, NifError> {
        Ok(term)
    }
}
<|endoftext|>