<commit_before>use std::fmt::{self, Write, Debug, Formatter};
use std::mem;
use std::ops::{Deref, DerefMut};

use gtk::signal::Inhibit;
use gdk::EventKey;

use logic::{Token, Tokens};
use logic::consts::ALLOWED_CHARS;

#[derive(Clone)]
pub struct Line {
	/// The line number of the proof, starting at 0. It is only visually where everything is incremented
	pub no: usize,
	/// A step of the proof. e.g. (P\^Q)->P. This is a vector of tokens that can be invalid.
	pub step: Tokens,
	/// A token string representing the method of the proof.
	pub method: Tokens,
	/// Line numbers that this depends on. Line numbers start at 0.
	pub deps: Vec<usize>,
}
impl Line {
	/// Constructs an empty line
	pub fn new(no: usize) -> Line {
		Line {
			no: no,
			step: Tokens::new(),
			method: Tokens::new(),
			deps: Vec::new(),
		}
	}
	/// Constructs a line with the specified tokens in the `step` field.
	pub fn with_step(no: usize, step: Tokens) -> Line {
		Line {
			no: no,
			step: step,
			method: Tokens::new(),
			deps: Vec::new(),
		}
	}
	pub fn full(no: usize, step: Tokens, method: Tokens, deps: Vec<usize>) -> Line {
		Line {
			no: no,
			step: step,
			method: method,
			deps: deps,
		}
	}

	pub fn fmt_cursor(&self, f: &mut Formatter, c: &Cursor) -> Result<(), fmt::Error> {
		let mut step_str = String::with_capacity(self.step.len() + 16);
		if !f.alternate() {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{}", t));
			}
		} else {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{:#}", t));
			}
		}
		if c.no == self.no && c.col == Col::Step && c.i == self.step.len() {
			step_str.push('|');
		}

		let mut dep_str = String::with_capacity(self.deps.len() * 2);
		for (i, dep) in self.deps.iter().enumerate() {
			try!(write!(dep_str, "{}", dep + 1));
			if i < self.deps.len() - 1 {
				dep_str.push_str(", ")
			}
		}

		let mut method_str = String::with_capacity(self.method.len() + 8);
		if c.no == self.no && c.col == Col::Method && (c.i <= self.method.len() || self.method.len() == 0) {
			let (a, b) = self.method.split_at(c.i);
			if !f.alternate() {
				for t in a {
					try!(write!(method_str, "{}", t));
				}
				method_str.push('|');
				for t in b {
					try!(write!(method_str, "{}", t));
				}
			} else {
				for t in a {
					try!(write!(method_str, "{:#}", t));
				}
				method_str.push('|');
				for t in b {
					try!(write!(method_str, "{:#}", t));
				}
			}
		} else {
			if !f.alternate() {
				for t in self.method.iter() {
					try!(write!(method_str, "{}", t));
				}
			} else {
				for t in self.method.iter() {
					try!(write!(method_str, "{:#}", t));
				}
			}
		}
		f.pad(&format!("{: >3}. {: <20} {: <10} {{{}}}", self.no + 1, step_str, method_str, dep_str))
	}

	/// True if `self.step` and `self.method` are empty
	pub fn is_empty(&self) -> bool {
		self.step.is_empty() && self.method.is_empty()
	}

	/// Simplifies all `Tokens` structs contained within this struct.
	pub fn simplify(&mut self) {
		self.step.simplify();
		self.method.simplify();
	}
}

#[derive(Clone)]
pub struct Lines {
	inner: Vec<Line>
}
impl Lines {
	/// Creates a lines object with one line.
	pub fn new() -> Lines {
		Lines {
			inner: vec![Line::new(0)]
		}
	}
	/// Creates a lines object from a vector.
	pub fn from_vec(v: Vec<Line>) -> Lines {
		Lines {
			inner: v
		}
	}

	/// Inserts `nl` at `nl.no` in `lines`, and updates all line numbers in `lines`
	pub fn insert_line(&mut self, nl: Line) {
		let no = nl.no;
		for l in self.iter_mut() {
			if l.no >= no {
				l.no += 1;
			}
		}
		self.insert(no, nl);
	}
	/// Deletes the line at `no` in `lines`, and updates all line numbers in `lines`
	pub fn delete_line(&mut self, no: usize) {
		self.inner.remove(no);
		for l in self.iter_mut() {
			if l.no >= no {
				l.no -= 1;
			}
		}
	}

	/// Simplifies all the lines that this structure holds.
	pub fn simplify(&mut self) {
		for l in self.iter_mut() {
			l.simplify();
		}
	}

	/// Inserts token `tok` at `cursor` pos.
	/// Returns Ok(n) with n being the number of tokens removed.
	pub fn insert_at(&mut self, cursor: &Cursor, tok: Token) -> Result<usize, ()> {
		let toks = match cursor.col {
			Col::Step   => &mut self[cursor.no].step,
			Col::Method => &mut self[cursor.no].method,
		};
		toks.insert(cursor.i, tok);
		let n = toks.simplify();
		Ok(n)
	}
}
impl Deref for Lines {
	type Target = Vec<Line>;
	fn deref(&self) -> &Vec<Line> {
		&self.inner
	}
}
impl DerefMut for Lines {
	fn deref_mut(&mut self) -> &mut Vec<Line> {
		&mut self.inner
	}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Col {
	Step,
	Method,
}
#[derive(Debug, PartialEq, Eq)]
pub struct Cursor {
	/// Line number
	no: usize,
	/// Column
	col: Col,
	/// Index of token/string
	i: usize,
}
impl Cursor {
	pub fn new() -> Cursor {
		Cursor {
			no: 0,
			col: Col::Step,
			i: 0,
		}
	}
	/// Move the cursor to the right. Wrap at end of line. Error at end of text.
	pub fn right(&mut self, lines: &[Line]) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { *self = Cursor::new(); return Err(()); },
		};
		self.i += 1;
		match self.col {
			Col::Step => {
				if self.i > l.step.len() {
					self.col = Col::Method;
					self.i = 0;
				}
				Ok(())
			}
			Col::Method => {
				if self.i > l.method.len() {
					if self.no < lines.len() - 1 {
						self.no += 1;
						self.col = Col::Step;
						self.i = 0;
						Ok(())
					} else {
						self.i -= 1;
						Err(())
					}
				} else {
					Ok(())
				}
			}
		}
	}
	/// Move the cursor to the left. Wrap at start of line. Error at start of text.
	pub fn left(&mut self, lines: &[Line]) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { *self = Cursor::new(); return Err(()); },
		};

		if self.i == 0 {
			match self.col {
				Col::Step => {
					if self.no > 0 {
						self.no -= 1;
						self.col = Col::Method;
						self.i = match lines.get(self.no) {
							Some(l) => l.method.len(),
							None    => { *self = Cursor::new(); return Err(()); },
						};
					}
				}
				Col::Method => {
					self.col = Col::Step;
					self.i = l.step.len();
				}
			}
		} else {
			self.i -= 1;
		}
		Ok(())
	}

	/// Is end of tokens
	/// Returns true if at the end of `Col::Step` or `Col::Method`
	fn is_eot(&self, lines: &Lines) -> bool {
		self.i == match self.col {
			Col::Step   => lines[self.no].step.len(),
			Col::Method => lines[self.no].method.len(),
		}
	}

	/// Delete the character in front of the cursor. If on an empty line && at the end, delete line. If no chars in front, returns `Err(())`.
	pub fn delete(&mut self, lines: &mut Lines) -> Result<(), ()> {
		if lines[self.no].is_empty() && self.col == Col::Method {
			if lines.len() == 1 {
				return Err(());
			}
			// Delete the line
			lines.delete_line(self.no);

			if self.no != 0 { self.no -= 1; };
			self.i = 0;

			Ok(())
		} else if self.is_eot(lines) {
			Err(())
		} else {
			// Delete char in front
			match self.col {
				Col::Step   => { let _ = lines[self.no].step.remove(self.i); },
				Col::Method => { let _ = lines[self.no].method.remove(self.i); },
			}
			Ok(())
		}
	}
	/// Delete the character behind the character. If on an empty line && at the start, delete line. If no chars behind, returns `Err(())`
	pub fn backspace(&mut self, lines: &mut Lines) -> Result<(), ()> {
		if lines[self.no].is_empty() && self.col == Col::Step {
			if lines.len() == 1 {
				return Err(());
			}
			// Delete the line
			lines.delete_line(self.no);

			if self.no != 0 { self.no -= 1; };
			self.i = 0;

			Ok(())
		} else if self.i == 0 {
			Err(())
		} else {
			// Delete char behind the cursor
			match self.col {
				Col::Step   => { let _ = lines[self.no].step.remove(self.i - 1); },
				Col::Method => { let _ = lines[self.no].method.remove(self.i - 1); },
			}
			self.i -= 1;
			Ok(())
		}
	}
	/// Add a newline to `lines` if the cursor is at the end of the line.
	pub fn newline(&mut self, lines: &mut Lines) -> Result<(), ()> {
		if !self.is_eot(lines) {
			// Don't place a newline if the cursor isn't at the end of the line.
			return Err(());
		}

		lines.insert_line(Line::new(self.no + 1));

		self.no += 1;
		self.i = 0;

		Ok(())
	}
	/// Inserts a token at the cursor pos in `lines`. Simplifies the line affected.
	pub fn insert(&mut self, lines: &mut Lines, c: Token) -> Result<(), ()> {
		let ret = lines.insert_at(self, c);
		if let Ok(n) = ret {
			self.i += 1;
			self.i -= n;
		}
		ret.map(|_| ())
	}
}

pub struct Editor {
	lines: Lines,
	cursor: Cursor,
}

impl<'a> Editor {
	/// Constructs a new editor
	pub fn new() -> Editor {
		Editor {
			lines: Lines::from_vec(vec![
			           Line::full(0, Tokens::from_str("P"), Tokens::from_str("Premise"), vec![0]),
			           Line::full(1, Tokens::from_str("¬¬P"), Tokens::from_str("¬I 1"), vec![0])
			       ]),
			cursor: Cursor::new(),
		}
	}
	/// Gets a ref to the line numbered `v` in the proof.
	pub fn line(&'a self, v: usize) -> Option<&'a Line> {
		self.lines.get(v - 1)
	}
	/// Gets the number of lines in the proof.
	pub fn lines(&self) -> usize {
		self.lines.len()
	}
	/// Handles the input given to it, and whether to pass the input on or not.
	pub fn handle_input(&mut self, e: &EventKey) -> Inhibit {
		use gdk::enums::key;
		use gdk::{keyval_to_unicode, keyval_name};

		let c = keyval_to_unicode(e.keyval).unwrap_or(' ');
		let name = keyval_name(e.keyval).unwrap_or(" ".to_string());
		println!("keypress: {0:#08x} : {1} : {2}", e.keyval, c, name);

		match unsafe { mem::transmute(e.keyval) } {
			key::Right => {
				let _ = self.cursor.right(&self.lines);
			},
			key::Left => {
				let _ = self.cursor.left(&self.lines);
			},
			key::Delete => {
				let _ = self.cursor.delete(&mut self.lines);
			},
			key::Return => {
				let _ = self.cursor.newline(&mut self.lines);
			},
			key::BackSpace => {
				let _ = self.cursor.backspace(&mut self.lines);
			},
			_ => {
				let _ = self.cursor.insert(&mut self.lines, match keyval_to_unicode(e.keyval) {
					Some(c) if c.is_alphabetic() || ALLOWED_CHARS.contains(c) => Token::Char(c),
					_ => { return Inhibit(false); },
				});
			}
		}
		println!(" *** Editor *** - Cursor: {:?} \n{:#?}", self.cursor, self);
		Inhibit(true)
	}
}
impl Debug for Editor {
	fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
		for l in self.lines.iter() {
			try!(l.fmt_cursor(f, &self.cursor));
			try!(writeln!(f, ""));
		}
		Ok(())
	}
}
<commit_msg>Replace &[Line] with Lines<commit_after>use std::fmt::{self, Write, Debug, Formatter};
use std::mem;
use std::ops::{Deref, DerefMut};

use gtk::signal::Inhibit;
use gdk::EventKey;

use logic::{Token, Tokens};
use logic::consts::ALLOWED_CHARS;

#[derive(Clone)]
pub struct Line {
	/// The line number of the proof, starting at 0. It is only visually where everything is incremented
	pub no: usize,
	/// A step of the proof. e.g. (P\^Q)->P. This is a vector of tokens that can be invalid.
	pub step: Tokens,
	/// A token string representing the method of the proof.
	pub method: Tokens,
	/// Line numbers that this depends on. Line numbers start at 0.
	pub deps: Vec<usize>,
}
impl Line {
	/// Constructs an empty line
	pub fn new(no: usize) -> Line {
		Line {
			no: no,
			step: Tokens::new(),
			method: Tokens::new(),
			deps: Vec::new(),
		}
	}
	/// Constructs a line with the specified tokens in the `step` field.
	pub fn with_step(no: usize, step: Tokens) -> Line {
		Line {
			no: no,
			step: step,
			method: Tokens::new(),
			deps: Vec::new(),
		}
	}
	pub fn full(no: usize, step: Tokens, method: Tokens, deps: Vec<usize>) -> Line {
		Line {
			no: no,
			step: step,
			method: method,
			deps: deps,
		}
	}

	pub fn fmt_cursor(&self, f: &mut Formatter, c: &Cursor) -> Result<(), fmt::Error> {
		let mut step_str = String::with_capacity(self.step.len() + 16);
		if !f.alternate() {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{}", t));
			}
		} else {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{:#}", t));
			}
		}
		if c.no == self.no && c.col == Col::Step && c.i == self.step.len() {
			step_str.push('|');
		}

		let mut dep_str = String::with_capacity(self.deps.len() * 2);
		for (i, dep) in self.deps.iter().enumerate() {
			try!(write!(dep_str, "{}", dep + 1));
			if i < self.deps.len() - 1 {
				dep_str.push_str(", ")
			}
		}

		let mut method_str = String::with_capacity(self.method.len() + 8);
		if c.no == self.no && c.col == Col::Method && (c.i <= self.method.len() || self.method.len() == 0) {
			let (a, b) = self.method.split_at(c.i);
			if !f.alternate() {
				for t in a {
					try!(write!(method_str, "{}", t));
				}
				method_str.push('|');
				for t in b {
					try!(write!(method_str, "{}", t));
				}
			} else {
				for t in a {
					try!(write!(method_str, "{:#}", t));
				}
				method_str.push('|');
				for t in b {
					try!(write!(method_str, "{:#}", t));
				}
			}
		} else {
			if !f.alternate() {
				for t in self.method.iter() {
					try!(write!(method_str, "{}", t));
				}
			} else {
				for t in self.method.iter() {
					try!(write!(method_str, "{:#}", t));
				}
			}
		}
		f.pad(&format!("{: >3}. {: <20} {: <10} {{{}}}", self.no + 1, step_str, method_str, dep_str))
	}

	/// True if `self.step` and `self.method` are empty
	pub fn is_empty(&self) -> bool {
		self.step.is_empty() && self.method.is_empty()
	}

	/// Simplifies all `Tokens` structs contained within this struct.
	pub fn simplify(&mut self) {
		self.step.simplify();
		self.method.simplify();
	}
}

#[derive(Clone)]
pub struct Lines {
	inner: Vec<Line>
}
impl Lines {
	/// Creates a lines object with one line.
	pub fn new() -> Lines {
		Lines {
			inner: vec![Line::new(0)]
		}
	}
	/// Creates a lines object from a vector.
	pub fn from_vec(v: Vec<Line>) -> Lines {
		Lines {
			inner: v
		}
	}

	/// Inserts `nl` at `nl.no` in `lines`, and updates all line numbers in `lines`
	pub fn insert_line(&mut self, nl: Line) {
		let no = nl.no;
		for l in self.iter_mut() {
			if l.no >= no {
				l.no += 1;
			}
		}
		self.insert(no, nl);
	}
	/// Deletes the line at `no` in `lines`, and updates all line numbers in `lines`
	pub fn delete_line(&mut self, no: usize) {
		self.inner.remove(no);
		for l in self.iter_mut() {
			if l.no >= no {
				l.no -= 1;
			}
		}
	}

	/// Simplifies all the lines that this structure holds.
	pub fn simplify(&mut self) {
		for l in self.iter_mut() {
			l.simplify();
		}
	}

	/// Inserts token `tok` at `cursor` pos.
	/// Returns Ok(n) with n being the number of tokens removed.
	pub fn insert_at(&mut self, cursor: &Cursor, tok: Token) -> Result<usize, ()> {
		let toks = match cursor.col {
			Col::Step   => &mut self[cursor.no].step,
			Col::Method => &mut self[cursor.no].method,
		};
		toks.insert(cursor.i, tok);
		let n = toks.simplify();
		Ok(n)
	}
}
impl Deref for Lines {
	type Target = Vec<Line>;
	fn deref(&self) -> &Vec<Line> {
		&self.inner
	}
}
impl DerefMut for Lines {
	fn deref_mut(&mut self) -> &mut Vec<Line> {
		&mut self.inner
	}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Col {
	Step,
	Method,
}
#[derive(Debug, PartialEq, Eq)]
pub struct Cursor {
	/// Line number
	no: usize,
	/// Column
	col: Col,
	/// Index of token/string
	i: usize,
}
impl Cursor {
	pub fn new() -> Cursor {
		Cursor {
			no: 0,
			col: Col::Step,
			i: 0,
		}
	}
	/// Move the cursor to the right. Wrap at end of line. Error at end of text.
	pub fn right(&mut self, lines: &Lines) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { *self = Cursor::new(); return Err(()); },
		};
		self.i += 1;
		match self.col {
			Col::Step => {
				if self.i > l.step.len() {
					self.col = Col::Method;
					self.i = 0;
				}
				Ok(())
			}
			Col::Method => {
				if self.i > l.method.len() {
					if self.no < lines.len() - 1 {
						self.no += 1;
						self.col = Col::Step;
						self.i = 0;
						Ok(())
					} else {
						self.i -= 1;
						Err(())
					}
				} else {
					Ok(())
				}
			}
		}
	}
	/// Move the cursor to the left. Wrap at start of line. Error at start of text.
	pub fn left(&mut self, lines: &Lines) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { *self = Cursor::new(); return Err(()); },
		};

		if self.i == 0 {
			match self.col {
				Col::Step => {
					if self.no > 0 {
						self.no -= 1;
						self.col = Col::Method;
						self.i = match lines.get(self.no) {
							Some(l) => l.method.len(),
							None    => { *self = Cursor::new(); return Err(()); },
						};
					}
				}
				Col::Method => {
					self.col = Col::Step;
					self.i = l.step.len();
				}
			}
		} else {
			self.i -= 1;
		}
		Ok(())
	}

	/// Is end of tokens
	/// Returns true if at the end of `Col::Step` or `Col::Method`
	fn is_eot(&self, lines: &Lines) -> bool {
		self.i == match self.col {
			Col::Step   => lines[self.no].step.len(),
			Col::Method => lines[self.no].method.len(),
		}
	}

	/// Delete the character in front of the cursor. If on an empty line && at the end, delete line. If no chars in front, returns `Err(())`.
	pub fn delete(&mut self, lines: &mut Lines) -> Result<(), ()> {
		if lines[self.no].is_empty() && self.col == Col::Method {
			if lines.len() == 1 {
				return Err(());
			}
			// Delete the line
			lines.delete_line(self.no);

			if self.no != 0 { self.no -= 1; };
			self.i = 0;

			Ok(())
		} else if self.is_eot(lines) {
			Err(())
		} else {
			// Delete char in front
			match self.col {
				Col::Step   => { let _ = lines[self.no].step.remove(self.i); },
				Col::Method => { let _ = lines[self.no].method.remove(self.i); },
			}
			Ok(())
		}
	}
	/// Delete the character behind the character. If on an empty line && at the start, delete line. If no chars behind, returns `Err(())`
	pub fn backspace(&mut self, lines: &mut Lines) -> Result<(), ()> {
		if lines[self.no].is_empty() && self.col == Col::Step {
			if lines.len() == 1 {
				return Err(());
			}
			// Delete the line
			lines.delete_line(self.no);

			if self.no != 0 { self.no -= 1; };
			self.i = 0;

			Ok(())
		} else if self.i == 0 {
			Err(())
		} else {
			// Delete char behind the cursor
			match self.col {
				Col::Step   => { let _ = lines[self.no].step.remove(self.i - 1); },
				Col::Method => { let _ = lines[self.no].method.remove(self.i - 1); },
			}
			self.i -= 1;
			Ok(())
		}
	}
	/// Add a newline to `lines` if the cursor is at the end of the line.
	pub fn newline(&mut self, lines: &mut Lines) -> Result<(), ()> {
		if !self.is_eot(lines) {
			// Don't place a newline if the cursor isn't at the end of the line.
			return Err(());
		}

		lines.insert_line(Line::new(self.no + 1));

		self.no += 1;
		self.i = 0;

		Ok(())
	}
	/// Inserts a token at the cursor pos in `lines`. Simplifies the line affected.
	pub fn insert(&mut self, lines: &mut Lines, c: Token) -> Result<(), ()> {
		let ret = lines.insert_at(self, c);
		if let Ok(n) = ret {
			self.i += 1;
			self.i -= n;
		}
		ret.map(|_| ())
	}
}

pub struct Editor {
	lines: Lines,
	cursor: Cursor,
}

impl<'a> Editor {
	/// Constructs a new editor
	pub fn new() -> Editor {
		Editor {
			lines: Lines::from_vec(vec![
			           Line::full(0, Tokens::from_str("P"), Tokens::from_str("Premise"), vec![0]),
			           Line::full(1, Tokens::from_str("¬¬P"), Tokens::from_str("¬I 1"), vec![0])
			       ]),
			cursor: Cursor::new(),
		}
	}
	/// Gets a ref to the line numbered `v` in the proof.
	pub fn line(&'a self, v: usize) -> Option<&'a Line> {
		self.lines.get(v - 1)
	}
	/// Gets the number of lines in the proof.
	pub fn lines(&self) -> usize {
		self.lines.len()
	}
	/// Handles the input given to it, and whether to pass the input on or not.
	pub fn handle_input(&mut self, e: &EventKey) -> Inhibit {
		use gdk::enums::key;
		use gdk::{keyval_to_unicode, keyval_name};

		let c = keyval_to_unicode(e.keyval).unwrap_or(' ');
		let name = keyval_name(e.keyval).unwrap_or(" ".to_string());
		println!("keypress: {0:#08x} : {1} : {2}", e.keyval, c, name);

		match unsafe { mem::transmute(e.keyval) } {
			key::Right => {
				let _ = self.cursor.right(&self.lines);
			},
			key::Left => {
				let _ = self.cursor.left(&self.lines);
			},
			key::Delete => {
				let _ = self.cursor.delete(&mut self.lines);
			},
			key::Return => {
				let _ = self.cursor.newline(&mut self.lines);
			},
			key::BackSpace => {
				let _ = self.cursor.backspace(&mut self.lines);
			},
			_ => {
				let _ = self.cursor.insert(&mut self.lines, match keyval_to_unicode(e.keyval) {
					Some(c) if c.is_alphabetic() || ALLOWED_CHARS.contains(c) => Token::Char(c),
					_ => { return Inhibit(false); },
				});
			}
		}
		println!(" *** Editor *** - Cursor: {:?} \n{:#?}", self.cursor, self);
		Inhibit(true)
	}
}
impl Debug for Editor {
	fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
		for l in self.lines.iter() {
			try!(l.fmt_cursor(f, &self.cursor));
			try!(writeln!(f, ""));
		}
		Ok(())
	}
}
<|endoftext|>


<commit_before>//! Defines the trait that must be implemented by ISPC task execution systems
//! and provides a default threaded one for use.

use libc;
use num_cpus;

use std::mem;
use std::cell::RefCell;
use std::sync::{Arc, RwLock, Mutex};
use std::sync::atomic::{self, AtomicUsize};
use std::thread::{self, JoinHandle};

use task::{ISPCTaskFn, Context};

/// Trait to be implemented to provide ISPC task execution functionality.
///
/// The runtime [required functions](http://ispc.github.io/ispc.html#task-parallelism-runtime-requirements)
/// will be forwarded directly to your struct, making this interface unsafe.
pub trait TaskSystem {
    /// Alloc is called when memory must be allocated to store parameters to pass to a task
    /// and must return a pointer to an allocation of `size` bytes aligned to `align`.
    ///
    /// The `handle_ptr` will be `NULL` if this is the first time launch has been called in
    /// the function or is the first launch call after an explicit `sync` statement. Both
    /// situations should be treated equivalently as creating a new exeuction context for tasks.
    /// The `handle_ptr` should be set to some context tracking facility so that you can later
    /// track task groups launched in the context and perform finer grained synchronization in
    /// `sync`.
    unsafe fn alloc(&self, handle_ptr: *mut *mut libc::c_void, size: i64, align: i32) -> *mut libc::c_void;
    /// Launch is called when a new group of tasks is being launched and should schedule them to
    /// be executed in some way.
    ///
    /// The `handle_ptr` will point to the same handle you set up in `alloc` and can be used to
    /// associate groups of tasks with a context of execution as mentioned before. The function `f`
    /// should be executed `count0 * count1 * count2` times and indices passed to the function
    /// should be as if running in a nested for loop:
    ///
    /// ```ignore
    /// let total_tasks = count0 * count1 * count2;
    /// for z in 0..count2 {
    ///     for y in 0..count1 {
    ///         for x in 0..count0 {
    ///             let task_id = x + y * count0 + z * count0 * count1;
    ///             f(data, thread_id, total_threads, task_id, total_tasks,
    ///               x, y, z, count0, count1, count2);
    ///         }
    ///     }
    /// }
    /// ```
    ///
    /// The `data` pointer points to the ISPC task specific parameter pointer and should be passed
    /// through to the function.
    unsafe fn launch(&self, handle_ptr: *mut *mut libc::c_void, f: ISPCTaskFn, data: *mut libc::c_void,
                     count0: i32, count1: i32, count2: i32);
    /// Synchronize an execution context with the tasks it's launched. Use `handle` to determine
    /// the task context being synchronized.
    ///
    /// This function should not return until all tasks launched within the context being
    /// synchronized with have been completed. You can use the `handle` to determine which context
    /// is being synchronized with and thus which tasks must be completed before returning.
    unsafe fn sync(&self, handle: *mut libc::c_void);
}

/// Thread local storage to store the thread's id, otherwise we don't know
/// who we are in sync. The thread id starts at an invalid value but will be set
/// upon thread launch
thread_local!(static THREAD_ID: RefCell<usize> = RefCell::new(0));

/// A multithreaded execution environment for the tasks.
pub struct Parallel {
    context_list: RwLock<Vec<Arc<Context>>>,
    next_context_id: AtomicUsize,
    threads: Mutex<Vec<JoinHandle<()>>>,
}

impl Parallel {
    pub fn new() -> Parallel {
        let par = Parallel { context_list: RwLock::new(Vec::new()),
                             next_context_id: AtomicUsize::new(0),
                             threads: Mutex::new(Vec::new()) };
        {
            let mut threads = par.threads.lock().unwrap();
            let num_threads = num_cpus::get();
            println!("Launching {} threads", num_threads);
            for i in 0..num_threads {
                // Note that the spawned thread ids start at 1 since the main thread is 0
                threads.push(thread::spawn(move || worker_thread(i + 1, num_threads + 1)));
            }
        }
        par
    }
}

impl TaskSystem for Parallel {
    unsafe fn alloc(&self, handle_ptr: *mut *mut libc::c_void, size: i64, align: i32) -> *mut libc::c_void {
        println!("ISPCAlloc, size: {}, align: {}", size, align);
        // If the handle is null this is the first time this function has spawned tasks
        // and we should create a new Context structure in the TASK_LIST for it, otherwise
        // it's the pointer to where we should append the new Group
        let mut context_list = self.context_list.write().unwrap();
        let context = if (*handle_ptr).is_null() {
            println!("handle ptr is null");
            // This is a bit hairy. We allocate the new task context in a box, then
            // unbox it into a raw ptr to get a ptr we can pass back to ISPC through
            // the handle_ptr and then re-box it into our TASK_LIST so it will
            // be free'd properly when we erase it from the vector in ISPCSync
            let c = Arc::new(Context::new(self.next_context_id.fetch_add(1, atomic::Ordering::SeqCst)));
            {
                let h = &*c;
                *handle_ptr = mem::transmute(h);
            }
            context_list.push(c);
            context_list.last_mut().unwrap()
        } else {
            // TODO: I'm not sure if it'd be worth optimizing this path to just require a read lock
            println!("handle ptr is not null");
            let handle_ctx: *mut Context = mem::transmute(*handle_ptr);
            context_list.iter_mut().find(|c| (*handle_ctx).id == c.id).unwrap()
        };
        println!("context.id = {}", context.id);
        context.alloc(size as usize, align as usize)
    }
    unsafe fn launch(&self, handle_ptr: *mut *mut libc::c_void, f: ISPCTaskFn, data: *mut libc::c_void,
                     count0: i32, count1: i32, count2: i32) {
        // Push the tasks being launched on to the list of task groups for this function
        let context: &mut Context = mem::transmute(*handle_ptr);
        println!("ISPCLaunch, context.id = {}, counts: [{}, {}, {}]", context.id, count0, count1, count2);
        context.launch((count0, count1, count2), data, f);
        // Unpark any sleeping threads since we have jobs for them
        let threads = self.threads.lock().unwrap();
        for t in threads.iter() {
            t.thread().unpark();
        }
    }
    unsafe fn sync(&self, handle: *mut libc::c_void) {
        let context: &mut Context = mem::transmute(handle);
        let thread = THREAD_ID.with(|f| *f.borrow());
        let total_threads = num_cpus::get();
        println!("Thread {} is syncing", thread);
        // Make sure all tasks are done, and execute them if not for this simple
        // serial version. TODO: In the future we'd wait on each Group's semaphore or atomic bool
        // Maybe the waiting thread could help execute tasks as well, otherwise it might be
        // possible to deadlock, where all threads are waiting for some enqueue'd tasks but no
        // threads are available to run them. Just running tasks in our context is not sufficient
        // to prevent deadlock actually, because those tasks could in turn launch & sync and get stuck
        // so if our tasks aren't done and there's none left to run in our context we should start
        // running tasks from other contexts to help out
        println!("ISPCSync, context.id = {}", context.id);
        for tg in context.iter() {
            for chunk in tg.chunks(1) {
                println!("syncing thread {} running local chunk {:?}", thread, chunk);
                // TODO: We need to figure out which thread we are
                chunk.execute(thread as i32, total_threads as i32);
            }
        }
        // If all the tasks for this context have been finished we're done sync'ing and can
        // clean up memory and remove the context from the TASK_LIST. Otherwise there are some
        // unfinished groups further down the the tree that were spawned by our direct tasks that
        // those are now sync'ing on and we need to help out. However since we don't know the tree
        // our best option is to just start grabbing chunks from unfinished groups in the TASK_LIST
        // and running them to at least ensure global forward progress, which will eventually get
        // the stuff we're waiting on to finish. After each chunk execution we should check if
        // our sync'ing context is done and break
        while !context.current_tasks_done() {
            println!("Not all tasks for context {} are done, thread {} helping out!", context.id, thread);
            // Get a task group to run
            let ctx = {
                // Do it in a block to limit the scope of the lock
                ::get_task_system().context_list.read().unwrap().iter()
                    .find(|c| !c.current_tasks_done()).map(|c| c.clone())
            };
            if let Some(c) = ctx {
                println!("syncing thread {} got a context {:?}", thread, c);
                for tg in c.iter() {
                    println!("syncing thread {} looking at task group {:?}", thread, tg);
                    for chunk in tg.chunks(1) {
                        println!("syncing thread {} running nonlocal chunk {:?}", thread, chunk);
                        chunk.execute(thread as i32, total_threads as i32);
                    }
                }
            } else {
                println!("Syncing thread didn't get a context");
            }
        }
        // Now erase this context from our vector
        let mut context_list = self.context_list.write().unwrap();
        let pos = context_list.iter().position(|c| context.id == c.id).unwrap();
        context_list.remove(pos);
    }
}

fn worker_thread(thread: usize, total_threads: usize) {
    THREAD_ID.with(|f| *f.borrow_mut() = thread);
    let task_system = ::get_task_system();
    println!("thread {} is spawned", thread);
    loop {
        thread::park();
        println!("thread {} was woken up to work!", thread);
        // Get a task group to run
        let ctx = {
            // Do it in a block to limit the scope of the lock
            task_system.context_list.read().unwrap().iter()
                .find(|c| !c.current_tasks_done()).map(|c| c.clone())
        };
        if let Some(c) = ctx {
            for tg in c.iter() {
                for chunk in tg.chunks(1) {
                    println!("thread {} running chunk {:?}", thread, chunk);
                    chunk.execute(thread as i32, total_threads as i32);
                }
            }
        }
    }
}

<commit_msg>Setting up to make chunk size configurable, make it a member<commit_after>//! Defines the trait that must be implemented by ISPC task execution systems
//! and provides a default threaded one for use.

use libc;
use num_cpus;

use std::mem;
use std::cell::RefCell;
use std::sync::{Arc, RwLock, Mutex};
use std::sync::atomic::{self, AtomicUsize};
use std::thread::{self, JoinHandle};

use task::{ISPCTaskFn, Context};

/// Trait to be implemented to provide ISPC task execution functionality.
///
/// The runtime [required functions](http://ispc.github.io/ispc.html#task-parallelism-runtime-requirements)
/// will be forwarded directly to your struct, making this interface unsafe.
pub trait TaskSystem {
    /// Alloc is called when memory must be allocated to store parameters to pass to a task
    /// and must return a pointer to an allocation of `size` bytes aligned to `align`.
    ///
    /// The `handle_ptr` will be `NULL` if this is the first time launch has been called in
    /// the function or is the first launch call after an explicit `sync` statement. Both
    /// situations should be treated equivalently as creating a new exeuction context for tasks.
    /// The `handle_ptr` should be set to some context tracking facility so that you can later
    /// track task groups launched in the context and perform finer grained synchronization in
    /// `sync`.
    unsafe fn alloc(&self, handle_ptr: *mut *mut libc::c_void, size: i64, align: i32) -> *mut libc::c_void;
    /// Launch is called when a new group of tasks is being launched and should schedule them to
    /// be executed in some way.
    ///
    /// The `handle_ptr` will point to the same handle you set up in `alloc` and can be used to
    /// associate groups of tasks with a context of execution as mentioned before. The function `f`
    /// should be executed `count0 * count1 * count2` times and indices passed to the function
    /// should be as if running in a nested for loop:
    ///
    /// ```ignore
    /// let total_tasks = count0 * count1 * count2;
    /// for z in 0..count2 {
    ///     for y in 0..count1 {
    ///         for x in 0..count0 {
    ///             let task_id = x + y * count0 + z * count0 * count1;
    ///             f(data, thread_id, total_threads, task_id, total_tasks,
    ///               x, y, z, count0, count1, count2);
    ///         }
    ///     }
    /// }
    /// ```
    ///
    /// The `data` pointer points to the ISPC task specific parameter pointer and should be passed
    /// through to the function.
    unsafe fn launch(&self, handle_ptr: *mut *mut libc::c_void, f: ISPCTaskFn, data: *mut libc::c_void,
                     count0: i32, count1: i32, count2: i32);
    /// Synchronize an execution context with the tasks it's launched. Use `handle` to determine
    /// the task context being synchronized.
    ///
    /// This function should not return until all tasks launched within the context being
    /// synchronized with have been completed. You can use the `handle` to determine which context
    /// is being synchronized with and thus which tasks must be completed before returning.
    unsafe fn sync(&self, handle: *mut libc::c_void);
}

/// Thread local storage to store the thread's id, otherwise we don't know
/// who we are in sync. The thread id starts at an invalid value but will be set
/// upon thread launch
thread_local!(static THREAD_ID: RefCell<usize> = RefCell::new(0));

/// A multithreaded execution environment for the tasks.
pub struct Parallel {
    context_list: RwLock<Vec<Arc<Context>>>,
    next_context_id: AtomicUsize,
    threads: Mutex<Vec<JoinHandle<()>>>,
    chunk_size: i32,
}

impl Parallel {
    pub fn new() -> Parallel {
        let par = Parallel { context_list: RwLock::new(Vec::new()),
                             next_context_id: AtomicUsize::new(0),
                             threads: Mutex::new(Vec::new()),
                             chunk_size: 8 };
        {
            let mut threads = par.threads.lock().unwrap();
            let num_threads = num_cpus::get();
            let chunk_size = par.chunk_size;
            println!("Launching {} threads", num_threads);
            for i in 0..num_threads {
                // Note that the spawned thread ids start at 1 since the main thread is 0
                threads.push(thread::spawn(move || worker_thread(i + 1, num_threads + 1, chunk_size)));
            }
        }
        par
    }
}

impl TaskSystem for Parallel {
    unsafe fn alloc(&self, handle_ptr: *mut *mut libc::c_void, size: i64, align: i32) -> *mut libc::c_void {
        println!("ISPCAlloc, size: {}, align: {}", size, align);
        // If the handle is null this is the first time this function has spawned tasks
        // and we should create a new Context structure in the TASK_LIST for it, otherwise
        // it's the pointer to where we should append the new Group
        let mut context_list = self.context_list.write().unwrap();
        let context = if (*handle_ptr).is_null() {
            println!("handle ptr is null");
            // This is a bit hairy. We allocate the new task context in a box, then
            // unbox it into a raw ptr to get a ptr we can pass back to ISPC through
            // the handle_ptr and then re-box it into our TASK_LIST so it will
            // be free'd properly when we erase it from the vector in ISPCSync
            let c = Arc::new(Context::new(self.next_context_id.fetch_add(1, atomic::Ordering::SeqCst)));
            {
                let h = &*c;
                *handle_ptr = mem::transmute(h);
            }
            context_list.push(c);
            context_list.last_mut().unwrap()
        } else {
            // TODO: I'm not sure if it'd be worth optimizing this path to just require a read lock
            println!("handle ptr is not null");
            let handle_ctx: *mut Context = mem::transmute(*handle_ptr);
            context_list.iter_mut().find(|c| (*handle_ctx).id == c.id).unwrap()
        };
        println!("context.id = {}", context.id);
        context.alloc(size as usize, align as usize)
    }
    unsafe fn launch(&self, handle_ptr: *mut *mut libc::c_void, f: ISPCTaskFn, data: *mut libc::c_void,
                     count0: i32, count1: i32, count2: i32) {
        // Push the tasks being launched on to the list of task groups for this function
        let context: &mut Context = mem::transmute(*handle_ptr);
        println!("ISPCLaunch, context.id = {}, counts: [{}, {}, {}]", context.id, count0, count1, count2);
        context.launch((count0, count1, count2), data, f);
        // Unpark any sleeping threads since we have jobs for them
        let threads = self.threads.lock().unwrap();
        for t in threads.iter() {
            t.thread().unpark();
        }
    }
    unsafe fn sync(&self, handle: *mut libc::c_void) {
        let context: &mut Context = mem::transmute(handle);
        let thread = THREAD_ID.with(|f| *f.borrow());
        let total_threads = num_cpus::get();
        println!("Thread {} is syncing", thread);
        // Make sure all tasks are done, and execute them if not for this simple
        // serial version. TODO: In the future we'd wait on each Group's semaphore or atomic bool
        // Maybe the waiting thread could help execute tasks as well, otherwise it might be
        // possible to deadlock, where all threads are waiting for some enqueue'd tasks but no
        // threads are available to run them. Just running tasks in our context is not sufficient
        // to prevent deadlock actually, because those tasks could in turn launch & sync and get stuck
        // so if our tasks aren't done and there's none left to run in our context we should start
        // running tasks from other contexts to help out
        println!("ISPCSync, context.id = {}", context.id);
        for tg in context.iter() {
            for chunk in tg.chunks(self.chunk_size) {
                println!("syncing thread {} running local chunk {:?}", thread, chunk);
                // TODO: We need to figure out which thread we are
                chunk.execute(thread as i32, total_threads as i32);
            }
        }
        // If all the tasks for this context have been finished we're done sync'ing and can
        // clean up memory and remove the context from the TASK_LIST. Otherwise there are some
        // unfinished groups further down the the tree that were spawned by our direct tasks that
        // those are now sync'ing on and we need to help out. However since we don't know the tree
        // our best option is to just start grabbing chunks from unfinished groups in the TASK_LIST
        // and running them to at least ensure global forward progress, which will eventually get
        // the stuff we're waiting on to finish. After each chunk execution we should check if
        // our sync'ing context is done and break
        while !context.current_tasks_done() {
            println!("Not all tasks for context {} are done, thread {} helping out!", context.id, thread);
            // Get a task group to run
            let ctx = {
                // Do it in a block to limit the scope of the lock
                ::get_task_system().context_list.read().unwrap().iter()
                    .find(|c| !c.current_tasks_done()).map(|c| c.clone())
            };
            if let Some(c) = ctx {
                println!("syncing thread {} got a context {:?}", thread, c);
                for tg in c.iter() {
                    println!("syncing thread {} looking at task group {:?}", thread, tg);
                    for chunk in tg.chunks(self.chunk_size) {
                        println!("syncing thread {} running nonlocal chunk {:?}", thread, chunk);
                        chunk.execute(thread as i32, total_threads as i32);
                    }
                }
            } else {
                println!("Syncing thread didn't get a context");
            }
        }
        // Now erase this context from our vector
        let mut context_list = self.context_list.write().unwrap();
        let pos = context_list.iter().position(|c| context.id == c.id).unwrap();
        context_list.remove(pos);
    }
}

fn worker_thread(thread: usize, total_threads: usize, chunk_size: i32) {
    THREAD_ID.with(|f| *f.borrow_mut() = thread);
    let task_system = ::get_task_system();
    println!("thread {} is spawned", thread);
    loop {
        thread::park();
        println!("thread {} was woken up to work!", thread);
        // Get a task group to run
        let ctx = {
            // Do it in a block to limit the scope of the lock
            task_system.context_list.read().unwrap().iter()
                .find(|c| !c.current_tasks_done()).map(|c| c.clone())
        };
        if let Some(c) = ctx {
            for tg in c.iter() {
                for chunk in tg.chunks(chunk_size) {
                    println!("thread {} running chunk {:?}", thread, chunk);
                    chunk.execute(thread as i32, total_threads as i32);
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>// boolean_expression: a Rust crate for Boolean expressions and BDDs.
//
// Copyright (c) 2016 Chris Fallin <cfallin@c1f.net>. Released under the MIT
// License.
//

use std::collections::HashMap;
use std::fmt::Debug;
use std::cmp::Ord;
use std::hash::Hash;

use simplify;

/// An `Expr` is a simple Boolean logic expression. It may contain terminals
/// (i.e., free variables), constants, and the following fundamental operations:
/// AND, OR, NOT.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    /// A terminal (free variable). This expression node represents a value that
    /// is not known until evaluation time.
    Terminal(T),
    /// A boolean constant: true or false.
    Const(bool),

    /// The logical complement of the contained expression argument.
    Not(Box<Expr<T>>),

    /// The logical AND of the two expression arguments.
    And(Box<Expr<T>>, Box<Expr<T>>),

    /// The logical OR of the two expression arguments.
    Or(Box<Expr<T>>, Box<Expr<T>>),
}

impl<T> Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    /// Returns `true` if this `Expr` is a terminal.
    pub fn is_terminal(&self) -> bool {
        match self {
            &Expr::Terminal(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is a constant.
    pub fn is_const(&self) -> bool {
        match self {
            &Expr::Const(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is a NOT node.
    pub fn is_not(&self) -> bool {
        match self {
            &Expr::Not(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is an AND node.
    pub fn is_and(&self) -> bool {
        match self {
            &Expr::And(_, _) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is an OR node.
    pub fn is_or(&self) -> bool {
        match self {
            &Expr::Or(_, _) => true,
            _ => false,
        }
    }

    /// Builds a NOT node around an argument, consuming the argument
    /// expression.
    pub fn not(e: Expr<T>) -> Expr<T> {
        Expr::Not(Box::new(e))
    }

    /// Builds an AND node around two arguments, consuming the argument
    /// expressions.
    pub fn and(e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
        Expr::And(Box::new(e1), Box::new(e2))
    }

    /// Builds an OR node around two arguments, consuming the argument
    /// expressions.
    pub fn or(e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
        Expr::Or(Box::new(e1), Box::new(e2))
    }

    /// Evaluates the expression with a particular set of terminal assignments.
    /// If any terminals are not assigned, they default to `false`.
    pub fn evaluate(&self, vals: &HashMap<T, bool>) -> bool {
        match self {
            &Expr::Terminal(ref t) => *vals.get(t).unwrap_or(&false),
            &Expr::Const(val) => val,
            &Expr::And(ref a, ref b) => a.evaluate(vals) && b.evaluate(vals),
            &Expr::Or(ref a, ref b) => a.evaluate(vals) || b.evaluate(vals),
            &Expr::Not(ref x) => !x.evaluate(vals),
        }
    }

    /// Simplify an expression in a relatively cheap way using well-known logic
    /// identities.
    ///
    /// This function performs certain reductions using DeMorgan's Law,
    /// distribution of ANDs over ORs, and certain identities involving
    /// constants, to simplify an expression. The result will always be in
    /// sum-of-products form: nodes will always appear in order (from
    /// expression tree root to leaves) `OR -> AND -> NOT`. In other words,
    /// `AND` nodes may only have `NOT` nodes (or terminals or constants) as
    /// children, and `NOT` nodes may only have terminals or constants as
    /// children.
    ///
    /// This function explicitly does *not* perform any sort of minterm reduction.
    /// The terms may thus be redundant (i.e., `And(a, b)` may appear twice), and
    /// combinable terms may exist (i.e., `And(a, b)` and `And(a, Not(b))` may
    /// appear in the `OR`'d list of terms, where these could be combined to
    /// simply `a` but are not). For example:
    ///
    /// ```
    /// use boolean_expression::Expr;
    ///
    /// // This simplifies using DeMorgan's Law:
    /// let expr = Expr::not(Expr::or(Expr::Terminal(0), Expr::Terminal(1)));
    /// let simplified = expr.simplify_via_laws();
    /// assert_eq!(simplified,
    ///     Expr::and(Expr::not(Expr::Terminal(0)),
    ///               Expr::not(Expr::Terminal(1))));
    ///
    /// // This doesn't simplify, though:
    /// let expr = Expr::or(
    ///             Expr::and(Expr::Terminal(0), Expr::Terminal(1)),
    ///             Expr::and(Expr::Terminal(0), Expr::not(Expr::Terminal(1))));
    /// let simplified = expr.clone().simplify_via_laws();
    /// assert_eq!(simplified, expr);
    /// ```
    ///
    /// For better (but more expensive) simplification, see `simplify_via_bdd()`.
    pub fn simplify_via_laws(self) -> Expr<T> {
        simplify::simplify_via_laws(self)
    }

    /// Simplify an expression via a roundtrip through a `BDD`. This procedure
    /// is more effective than `Expr::simplify_via_laws()`, but more expensive.
    /// This roundtrip will implicitly simplify an arbitrarily complicated
    /// function (by construction, as the BDD is built), and then find a
    /// quasi-minimal set of terms using cubelist-based reduction. For example:
    ///
    /// ```
    /// use boolean_expression::Expr;
    ///
    /// // `simplify_via_laws()` cannot combine these terms, but
    /// // `simplify_via_bdd()` will:
    /// let expr = Expr::or(
    ///             Expr::and(Expr::Terminal(0), Expr::Terminal(1)),
    ///             Expr::and(Expr::Terminal(0), Expr::not(Expr::Terminal(1))));
    /// let simplified = expr.simplify_via_bdd();
    /// assert_eq!(simplified, Expr::Terminal(0));
    /// ```
    pub fn simplify_via_bdd(self) -> Expr<T> {
        simplify::simplify_via_bdd(self)
    }

    /// Map terminal values using the specified mapping function.
    pub fn map<F, R>(&self, f: F) -> Expr<R>
    where
        F: Fn(&T) -> R,
        R: Clone + Debug + Eq + Hash,
    {
        self.map1(&f)
    }

    fn map1<F, R>(&self, f: &F) -> Expr<R>
    where
        F: Fn(&T) -> R,
        R: Clone + Debug + Eq + Hash,
    {
        match self {
            &Expr::Terminal(ref t) => Expr::Terminal(f(t)),
            &Expr::Const(val) => Expr::Const(val),
            &Expr::Not(ref n) => Expr::not(n.map1(f)),
            &Expr::And(ref a, ref b) => Expr::and(a.map1(f), b.map1(f)),
            &Expr::Or(ref a, ref b) => Expr::or(a.map1(f), b.map1(f)),
        }
    }
}
<commit_msg>Implement bit operators for Expr<commit_after>// boolean_expression: a Rust crate for Boolean expressions and BDDs.
//
// Copyright (c) 2016 Chris Fallin <cfallin@c1f.net>. Released under the MIT
// License.
//

use std::collections::HashMap;
use std::fmt::Debug;
use std::cmp::Ord;
use std::hash::Hash;
use std::ops::BitAnd;
use std::ops::BitAndAssign;
use std::ops::BitOr;
use std::ops::BitOrAssign;
use std::ops::Not;

use simplify;

/// An `Expr` is a simple Boolean logic expression. It may contain terminals
/// (i.e., free variables), constants, and the following fundamental operations:
/// AND, OR, NOT.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    /// A terminal (free variable). This expression node represents a value that
    /// is not known until evaluation time.
    Terminal(T),
    /// A boolean constant: true or false.
    Const(bool),

    /// The logical complement of the contained expression argument.
    Not(Box<Expr<T>>),

    /// The logical AND of the two expression arguments.
    And(Box<Expr<T>>, Box<Expr<T>>),

    /// The logical OR of the two expression arguments.
    Or(Box<Expr<T>>, Box<Expr<T>>),
}

impl<T> Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    /// Returns `true` if this `Expr` is a terminal.
    pub fn is_terminal(&self) -> bool {
        match self {
            &Expr::Terminal(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is a constant.
    pub fn is_const(&self) -> bool {
        match self {
            &Expr::Const(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is a NOT node.
    pub fn is_not(&self) -> bool {
        match self {
            &Expr::Not(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is an AND node.
    pub fn is_and(&self) -> bool {
        match self {
            &Expr::And(_, _) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is an OR node.
    pub fn is_or(&self) -> bool {
        match self {
            &Expr::Or(_, _) => true,
            _ => false,
        }
    }

    /// Builds a NOT node around an argument, consuming the argument
    /// expression.
    pub fn not(e: Expr<T>) -> Expr<T> {
        Expr::Not(Box::new(e))
    }

    /// Builds an AND node around two arguments, consuming the argument
    /// expressions.
    pub fn and(e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
        Expr::And(Box::new(e1), Box::new(e2))
    }

    /// Builds an OR node around two arguments, consuming the argument
    /// expressions.
    pub fn or(e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
        Expr::Or(Box::new(e1), Box::new(e2))
    }

    /// Evaluates the expression with a particular set of terminal assignments.
    /// If any terminals are not assigned, they default to `false`.
    pub fn evaluate(&self, vals: &HashMap<T, bool>) -> bool {
        match self {
            &Expr::Terminal(ref t) => *vals.get(t).unwrap_or(&false),
            &Expr::Const(val) => val,
            &Expr::And(ref a, ref b) => a.evaluate(vals) && b.evaluate(vals),
            &Expr::Or(ref a, ref b) => a.evaluate(vals) || b.evaluate(vals),
            &Expr::Not(ref x) => !x.evaluate(vals),
        }
    }

    /// Simplify an expression in a relatively cheap way using well-known logic
    /// identities.
    ///
    /// This function performs certain reductions using DeMorgan's Law,
    /// distribution of ANDs over ORs, and certain identities involving
    /// constants, to simplify an expression. The result will always be in
    /// sum-of-products form: nodes will always appear in order (from
    /// expression tree root to leaves) `OR -> AND -> NOT`. In other words,
    /// `AND` nodes may only have `NOT` nodes (or terminals or constants) as
    /// children, and `NOT` nodes may only have terminals or constants as
    /// children.
    ///
    /// This function explicitly does *not* perform any sort of minterm reduction.
    /// The terms may thus be redundant (i.e., `And(a, b)` may appear twice), and
    /// combinable terms may exist (i.e., `And(a, b)` and `And(a, Not(b))` may
    /// appear in the `OR`'d list of terms, where these could be combined to
    /// simply `a` but are not). For example:
    ///
    /// ```
    /// use boolean_expression::Expr;
    ///
    /// // This simplifies using DeMorgan's Law:
    /// let expr = Expr::not(Expr::or(Expr::Terminal(0), Expr::Terminal(1)));
    /// let simplified = expr.simplify_via_laws();
    /// assert_eq!(simplified,
    ///     Expr::and(Expr::not(Expr::Terminal(0)),
    ///               Expr::not(Expr::Terminal(1))));
    ///
    /// // This doesn't simplify, though:
    /// let expr = Expr::or(
    ///             Expr::and(Expr::Terminal(0), Expr::Terminal(1)),
    ///             Expr::and(Expr::Terminal(0), Expr::not(Expr::Terminal(1))));
    /// let simplified = expr.clone().simplify_via_laws();
    /// assert_eq!(simplified, expr);
    /// ```
    ///
    /// For better (but more expensive) simplification, see `simplify_via_bdd()`.
    pub fn simplify_via_laws(self) -> Expr<T> {
        simplify::simplify_via_laws(self)
    }

    /// Simplify an expression via a roundtrip through a `BDD`. This procedure
    /// is more effective than `Expr::simplify_via_laws()`, but more expensive.
    /// This roundtrip will implicitly simplify an arbitrarily complicated
    /// function (by construction, as the BDD is built), and then find a
    /// quasi-minimal set of terms using cubelist-based reduction. For example:
    ///
    /// ```
    /// use boolean_expression::Expr;
    ///
    /// // `simplify_via_laws()` cannot combine these terms, but
    /// // `simplify_via_bdd()` will:
    /// let expr = Expr::or(
    ///             Expr::and(Expr::Terminal(0), Expr::Terminal(1)),
    ///             Expr::and(Expr::Terminal(0), Expr::not(Expr::Terminal(1))));
    /// let simplified = expr.simplify_via_bdd();
    /// assert_eq!(simplified, Expr::Terminal(0));
    /// ```
    pub fn simplify_via_bdd(self) -> Expr<T> {
        simplify::simplify_via_bdd(self)
    }

    /// Map terminal values using the specified mapping function.
    pub fn map<F, R>(&self, f: F) -> Expr<R>
    where
        F: Fn(&T) -> R,
        R: Clone + Debug + Eq + Hash,
    {
        self.map1(&f)
    }

    fn map1<F, R>(&self, f: &F) -> Expr<R>
    where
        F: Fn(&T) -> R,
        R: Clone + Debug + Eq + Hash,
    {
        match self {
            &Expr::Terminal(ref t) => Expr::Terminal(f(t)),
            &Expr::Const(val) => Expr::Const(val),
            &Expr::Not(ref n) => Expr::not(n.map1(f)),
            &Expr::And(ref a, ref b) => Expr::and(a.map1(f), b.map1(f)),
            &Expr::Or(ref a, ref b) => Expr::or(a.map1(f), b.map1(f)),
        }
    }
}

impl<T> Not for Expr<T>
where
    T: Clone + Debug + Eq + Hash
{
    type Output = Self;

    fn not(self) -> Self::Output {
        Self::not(self)
    }
}

impl<T> BitAnd<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash
{
    type Output = Self;

    fn bitand(self, rhs: Expr<T>) -> Self::Output {
        Self::and(self, rhs)
    }
}

impl<T> BitAndAssign<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash
{
    fn bitand_assign(&mut self, rhs: Expr<T>) {
        *self = Self::and(self.clone(), rhs);
    }
}

impl<T> BitOr<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash
{
    type Output = Self;

    fn bitor(self, rhs: Expr<T>) -> Self::Output {
        Self::or(self, rhs)
    }
}

impl<T> BitOrAssign<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash
{
    fn bitor_assign(&mut self, rhs: Expr<T>) {
        *self = Self::or(self.clone(), rhs);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ops;
use std::num::Zero;
use std::cmp::{PartialEq, PartialOrd};

pub trait NumType: fmt::Debug+Clone+Zero+ops::Add<Output=Self>+ops::Sub<Output=Self>+ops::Mul<Output=Self>+ops::Div<Output=Self>+PartialEq+PartialOrd+Default {}

impl NumType for f32 {}
impl NumType for f64 {}
impl NumType for u32 {}
impl NumType for u64 {}

#[derive(Debug, Eq, PartialEq)]
pub enum ExprError {
    /// In case of division by zero.
    DivByZero,
    /// When the argument position `n` in Arg(n) is out of bounds.
    InvalidArg,
    /// In case of an invalid operation.
    InvalidOperation,
}

/// An expression evaluates to a numeric value of `NumType`.
#[derive(Clone, PartialEq, Eq)]
pub enum Expr<T: NumType> {
    Const(T),
    // References an actual Argument by position
    Arg(usize),
    Add(Box<Expr<T>>, Box<Expr<T>>),
    Sub(Box<Expr<T>>, Box<Expr<T>>),
    Mul(Box<Expr<T>>, Box<Expr<T>>),
    Div(Box<Expr<T>>, Box<Expr<T>>),
}

impl<T:NumType> fmt::Debug for Expr<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Expr::Const(ref c) => write!(f, "{:?}", c),
            &Expr::Arg(num) => write!(f, "a{}", num),
            &Expr::Add(ref op1, ref op2) => write!(f, "({:?}+{:?})", op1, op2),
            &Expr::Sub(ref op1, ref op2) => write!(f, "({:?}-{:?})", op1, op2),
            &Expr::Mul(ref op1, ref op2) => write!(f, "{:?}*{:?}", op1, op2),
            &Expr::Div(ref op1, ref op2) => write!(f, "{:?}/{:?}", op1, op2),
        }
    }
}

impl<T:NumType> Expr<T> {
    pub fn value(&self) -> Result<T, ExprError> {
        if let &Expr::Const(ref c) = self {
            Ok(c.clone())
        } else {
            Err(ExprError::InvalidArg)
        }
    }

    pub fn evaluate(&self, args: &[Expr<T>]) -> Result<T, ExprError> {
        Ok(match *self {
            Expr::Arg(n) => {
                try!(try!(args.get(n).ok_or(ExprError::InvalidArg)).value())
            }
            Expr::Const(ref c) => c.clone(),
            Expr::Add(ref e1, ref e2) => try!(e1.evaluate(args)) + try!(e2.evaluate(args)),
            Expr::Sub(ref e1, ref e2) => try!(e1.evaluate(args)) - try!(e2.evaluate(args)),
            Expr::Mul(ref e1, ref e2) => try!(e1.evaluate(args)) * try!(e2.evaluate(args)),
            Expr::Div(ref e1, ref e2) => {
                let a = try!(e1.evaluate(args));
                let b = try!(e2.evaluate(args));
                if b == T::zero() {
                    return Err(ExprError::DivByZero);
                }
                a / b
            }
        })
    }
}

/// A condition evaluates to either `true` or `false`.
#[derive(Debug, Clone)]
pub enum Condition<T: NumType> {
    True,
    False,
    Not(Box<Condition<T>>),
    And(Box<Condition<T>>, Box<Condition<T>>),
    Or(Box<Condition<T>>, Box<Condition<T>>),

    /// If two expressions are equal
    Equal(Box<Expr<T>>, Box<Expr<T>>),

    Less(Box<Expr<T>>, Box<Expr<T>>),
    Greater(Box<Expr<T>>, Box<Expr<T>>),

    LessEqual(Box<Expr<T>>, Box<Expr<T>>),
    GreaterEqual(Box<Expr<T>>, Box<Expr<T>>),
}

impl<T:NumType> Condition<T> {
    pub fn evaluate(&self, args: &[Expr<T>]) -> Result<bool, ExprError> {
        Ok(match *self {
            Condition::True => true,
            Condition::False => false,
            Condition::Not(ref c) => !try!(c.evaluate(args)),
            Condition::And(ref c1, ref c2) => try!(c1.evaluate(args)) && try!(c2.evaluate(args)),
            Condition::Or(ref c1, ref c2) => try!(c1.evaluate(args)) || try!(c2.evaluate(args)),
            Condition::Equal(ref e1, ref e2) => try!(e1.evaluate(args)) == try!(e2.evaluate(args)),
            Condition::Less(ref e1, ref e2) => try!(e1.evaluate(args)) < try!(e2.evaluate(args)),
            Condition::Greater(ref e1, ref e2) => try!(e1.evaluate(args)) > try!(e2.evaluate(args)),
            Condition::LessEqual(ref e1, ref e2) =>
                try!(e1.evaluate(args)) <= try!(e2.evaluate(args)),
            Condition::GreaterEqual(ref e1, ref e2) =>
                try!(e1.evaluate(args)) >= try!(e2.evaluate(args)),
        })
    }
}

#[test]
fn test_expr() {
    let expr = Expr::Sub(box Expr::Const(0.0),
                         box Expr::Div(box Expr::Mul(box Expr::Add(box Expr::Const(1.0),
                                                                   box Expr::Arg(0)),
                                                     box Expr::Arg(1)),
                                       box Expr::Const(2.0)));

    fn fun(a: f32, b: f32) -> f32 {
        0.0 - ((1.0 + a) * b) / 2.0
    }

    fn check(expr: &Expr<f32>, a: f32, b: f32) {
        assert_eq!(Ok(fun(a, b)),
                   expr.evaluate(&[Expr::Const(a), Expr::Const(b)]))
    }

    check(&expr, 123.0, 4444.0);
    check(&expr, 0.0, -12.0);
}

#[test]
fn test_condition() {
    let cond = Condition::Greater(box Expr::Arg(0), box Expr::Const(0.0));

    fn fun(a: f32) -> bool {
        a > 0.0
    }

    fn check(cond: &Condition<f32>, a: f32) {
        assert_eq!(Ok(fun(a)), cond.evaluate(&[Expr::Const(a)]))
    }

    check(&cond, 123.0);
    check(&cond, 0.0);
    check(&cond, -1.4);

    assert_eq!(Ok(true), (Condition::True::<f32>).evaluate(&[]));
}
<commit_msg>Add Expr::Divz, a safe division which return 0.0 instead of a div-by-zero error.<commit_after>use std::fmt;
use std::ops;
use std::num::Zero;
use std::cmp::{PartialEq, PartialOrd};

pub trait NumType: fmt::Debug+Clone+Zero+ops::Add<Output=Self>+ops::Sub<Output=Self>+ops::Mul<Output=Self>+ops::Div<Output=Self>+PartialEq+PartialOrd+Default {}

impl NumType for f32 {}
impl NumType for f64 {}
impl NumType for u32 {}
impl NumType for u64 {}

#[derive(Debug, Eq, PartialEq)]
pub enum ExprError {
    /// In case of division by zero.
    DivByZero,
    /// When the argument position `n` in Arg(n) is out of bounds.
    InvalidArg,
    /// In case of an invalid operation.
    InvalidOperation,
}

/// An expression evaluates to a numeric value of `NumType`.
#[derive(Clone, PartialEq, Eq)]
pub enum Expr<T: NumType> {
    Const(T),
    // References an actual Argument by position
    Arg(usize),
    Add(Box<Expr<T>>, Box<Expr<T>>),
    Sub(Box<Expr<T>>, Box<Expr<T>>),
    Mul(Box<Expr<T>>, Box<Expr<T>>),
    Div(Box<Expr<T>>, Box<Expr<T>>),

    // Safe division with x/0 = 0.0
    Divz(Box<Expr<T>>, Box<Expr<T>>),
}

impl<T:NumType> fmt::Debug for Expr<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Expr::Const(ref c) => write!(f, "{:?}", c),
            &Expr::Arg(num) => write!(f, "a{}", num),
            &Expr::Add(ref op1, ref op2) => write!(f, "({:?}+{:?})", op1, op2),
            &Expr::Sub(ref op1, ref op2) => write!(f, "({:?}-{:?})", op1, op2),
            &Expr::Mul(ref op1, ref op2) => write!(f, "{:?}*{:?}", op1, op2),
            &Expr::Div(ref op1, ref op2) => write!(f, "{:?}/{:?}", op1, op2),
            &Expr::Divz(ref op1, ref op2) => write!(f, "{:?}\\{:?}", op1, op2),
        }
    }
}

impl<T:NumType> Expr<T> {
    pub fn value(&self) -> Result<T, ExprError> {
        if let &Expr::Const(ref c) = self {
            Ok(c.clone())
        } else {
            Err(ExprError::InvalidArg)
        }
    }

    pub fn evaluate(&self, args: &[Expr<T>]) -> Result<T, ExprError> {
        Ok(match *self {
            Expr::Arg(n) => {
                try!(try!(args.get(n).ok_or(ExprError::InvalidArg)).value())
            }
            Expr::Const(ref c) => c.clone(),
            Expr::Add(ref e1, ref e2) => try!(e1.evaluate(args)) + try!(e2.evaluate(args)),
            Expr::Sub(ref e1, ref e2) => try!(e1.evaluate(args)) - try!(e2.evaluate(args)),
            Expr::Mul(ref e1, ref e2) => try!(e1.evaluate(args)) * try!(e2.evaluate(args)),
            Expr::Div(ref e1, ref e2) => {
                let a = try!(e1.evaluate(args));
                let b = try!(e2.evaluate(args));
                if b == T::zero() {
                    return Err(ExprError::DivByZero);
                }
                a / b
            }
            Expr::Divz(ref e1, ref e2) => {
                let a = try!(e1.evaluate(args));
                let b = try!(e2.evaluate(args));
                if b == T::zero() {
                    b
                } else {
                    a / b
                }
            }
        })
    }
}

/// A condition evaluates to either `true` or `false`.
#[derive(Debug, Clone)]
pub enum Condition<T: NumType> {
    True,
    False,
    Not(Box<Condition<T>>),
    And(Box<Condition<T>>, Box<Condition<T>>),
    Or(Box<Condition<T>>, Box<Condition<T>>),

    /// If two expressions are equal
    Equal(Box<Expr<T>>, Box<Expr<T>>),

    Less(Box<Expr<T>>, Box<Expr<T>>),
    Greater(Box<Expr<T>>, Box<Expr<T>>),

    LessEqual(Box<Expr<T>>, Box<Expr<T>>),
    GreaterEqual(Box<Expr<T>>, Box<Expr<T>>),
}

impl<T:NumType> Condition<T> {
    pub fn evaluate(&self, args: &[Expr<T>]) -> Result<bool, ExprError> {
        Ok(match *self {
            Condition::True => true,
            Condition::False => false,
            Condition::Not(ref c) => !try!(c.evaluate(args)),
            Condition::And(ref c1, ref c2) => try!(c1.evaluate(args)) && try!(c2.evaluate(args)),
            Condition::Or(ref c1, ref c2) => try!(c1.evaluate(args)) || try!(c2.evaluate(args)),
            Condition::Equal(ref e1, ref e2) => try!(e1.evaluate(args)) == try!(e2.evaluate(args)),
            Condition::Less(ref e1, ref e2) => try!(e1.evaluate(args)) < try!(e2.evaluate(args)),
            Condition::Greater(ref e1, ref e2) => try!(e1.evaluate(args)) > try!(e2.evaluate(args)),
            Condition::LessEqual(ref e1, ref e2) =>
                try!(e1.evaluate(args)) <= try!(e2.evaluate(args)),
            Condition::GreaterEqual(ref e1, ref e2) =>
                try!(e1.evaluate(args)) >= try!(e2.evaluate(args)),
        })
    }
}

#[test]
fn test_expr_divz() {
    let expr = Expr::Divz(box Expr::Const(1.0), box Expr::Const(0.0));
    assert_eq!(Ok(0.0), expr.evaluate(&[]));
}

#[test]
fn test_expr() {
    let expr = Expr::Sub(box Expr::Const(0.0),
                         box Expr::Div(box Expr::Mul(box Expr::Add(box Expr::Const(1.0),
                                                                   box Expr::Arg(0)),
                                                     box Expr::Arg(1)),
                                       box Expr::Const(2.0)));

    fn fun(a: f32, b: f32) -> f32 {
        0.0 - ((1.0 + a) * b) / 2.0
    }

    fn check(expr: &Expr<f32>, a: f32, b: f32) {
        assert_eq!(Ok(fun(a, b)),
                   expr.evaluate(&[Expr::Const(a), Expr::Const(b)]))
    }

    check(&expr, 123.0, 4444.0);
    check(&expr, 0.0, -12.0);
}

#[test]
fn test_condition() {
    let cond = Condition::Greater(box Expr::Arg(0), box Expr::Const(0.0));

    fn fun(a: f32) -> bool {
        a > 0.0
    }

    fn check(cond: &Condition<f32>, a: f32) {
        assert_eq!(Ok(fun(a)), cond.evaluate(&[Expr::Const(a)]))
    }

    check(&cond, 123.0);
    check(&cond, 0.0);
    check(&cond, -1.4);

    assert_eq!(Ok(true), (Condition::True::<f32>).evaluate(&[]));
}
<|endoftext|>


<commit_before>use std;
use hb;
use libc::c_void;

use std::marker::PhantomData;

use blob::Blob;
use common::{HarfbuzzObject, HbArc, HbBox, Tag};

/// A wrapper around `hb_face_t`.
#[derive(Debug)]
pub struct Face<'a> {
    hb_face: hb::hb_face_t,
    _marker: PhantomData<&'a [u8]>,
}

use std::path::Path;

impl<'a> Face<'a> {
    /// Create a new `Face` from the data in `bytes`.
    pub fn new<'b, T: Into<HbArc<Blob<'b>>>>(bytes: T, index: u32) -> HbBox<Face<'b>> {
        let blob = bytes.into();
        let hb_face = unsafe { hb::hb_face_create(HbArc::into_raw(blob), index) };
        unsafe { HbBox::from_raw(hb_face) }
    }

    /// Create a new face from the contents of the file at `path`.
    pub fn from_file<P: AsRef<Path>>(path: P, index: u32) -> std::io::Result<HbBox<Face<'static>>> {
        let blob = Blob::from_file(path)?;
        Ok(Face::new(blob, index))
    }

    /// Create a new face from a closure that returns a raw [`Blob`](struct.Blob.html) of table
    pub fn from_table_func<'b, F>(func: F) -> HbBox<Face<'b>>
    where
        F: FnMut(Tag) -> Option<HbArc<Blob<'b>>>,
    {
        extern "C" fn destroy_box<U>(ptr: *mut c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }
        extern "C" fn table_func<'b, F>(
            _: *mut hb::hb_face_t,
            tag: hb::hb_tag_t,
            user_data: *mut c_void,
        ) -> *mut hb::hb_blob_t
        where
            F: FnMut(Tag) -> Option<HbArc<Blob<'b>>>,
        {
            let tag = Tag(tag);
            let closure = unsafe { &mut *(user_data as *mut F) };
            let blob = closure(tag);
            match blob {
                Some(blob) => HbArc::into_raw(blob),
                None => std::ptr::null_mut(),
            }
        }
        let boxed_closure = Box::new(func);
        unsafe {
            let face = hb::hb_face_create_for_tables(
                Some(table_func::<'b, F>),
                Box::into_raw(boxed_closure) as *mut _,
                Some(destroy_box::<F>),
            );
            HbBox::from_raw(face)
        }
    }

    //    /// Create a `Font` of this face. By default this will use harfbuzz' included opentype
    // font
    //    /// funcs for shaping and have no scale value set so that the returned values will be in
    // font
    //    /// space.
    //    pub fn create_font(self) -> HbBox<Font<'a>> {
    //        Font::new(self)
    //    }

    pub fn face_data(&self) -> &'a [u8] {
        unsafe {
            let raw_blob = hb::hb_face_reference_blob(self.as_raw());
            Blob::from_raw(raw_blob).get_data()
        }
    }

    pub fn table_with_tag(&self, tag: Tag) -> Option<&[u8]> {
        unsafe {
            let raw_blob = hb::hb_face_reference_table(self.as_raw(), tag.0);
            if raw_blob.is_null() {
                None
            } else {
                let blob = Blob::from_raw(raw_blob);
                if blob.is_empty() {
                    None
                } else {
                    Some(blob.get_data())
                }
            }
        }
    }

    pub fn index(&self) -> u32 {
        unsafe { hb::hb_face_get_index(self.as_raw()) }
    }

    pub fn set_upem(&mut self, upem: u32) {
        unsafe { hb::hb_face_set_upem(self.as_raw(), upem) };
    }

    pub fn upem(&self) -> u32 {
        unsafe { hb::hb_face_get_upem(self.as_raw()) }
    }

    pub fn set_glyph_count(&mut self, count: u32) {
        unsafe { hb::hb_face_set_glyph_count(self.as_raw(), count) };
    }

    pub fn glyph_count(&self) -> u32 {
        unsafe { hb::hb_face_get_glyph_count(self.as_raw()) }
    }
}

impl<'a> HarfbuzzObject for Face<'a> {
    type Raw = hb::hb_face_t;

    unsafe fn reference(&self) {
        hb::hb_face_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_face_destroy(self.as_raw());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use common::Tag;

    #[test]
    fn test_face_from_table_func() {
        let face = Face::from_table_func(|table_tag| {
            let content = format!("{}-table", table_tag);
            Some(content.into_bytes().into())
        });

        let maxp_table = face.table_with_tag(Tag::new('m', 'a', 'x', 'p')).unwrap();
        assert_eq!(maxp_table, b"maxp-table");

        let maxp_table = face.table_with_tag(Tag::new('h', 'h', 'e', 'a')).unwrap();
        assert_eq!(maxp_table, b"hhea-table");
    }
}
<commit_msg>Face: Add Send+Sync bound to closure<commit_after>use std;
use hb;
use libc::c_void;

use std::marker::PhantomData;

use blob::Blob;
use common::{HarfbuzzObject, HbArc, HbBox, Tag};

/// A wrapper around `hb_face_t`.
#[derive(Debug)]
pub struct Face<'a> {
    hb_face: hb::hb_face_t,
    _marker: PhantomData<&'a [u8]>,
}

use std::path::Path;

impl<'a> Face<'a> {
    /// Create a new `Face` from the data in `bytes`.
    pub fn new<'b, T: Into<HbArc<Blob<'b>>>>(bytes: T, index: u32) -> HbBox<Face<'b>> {
        let blob = bytes.into();
        let hb_face = unsafe { hb::hb_face_create(HbArc::into_raw(blob), index) };
        unsafe { HbBox::from_raw(hb_face) }
    }

    /// Create a new face from the contents of the file at `path`.
    pub fn from_file<P: AsRef<Path>>(path: P, index: u32) -> std::io::Result<HbBox<Face<'static>>> {
        let blob = Blob::from_file(path)?;
        Ok(Face::new(blob, index))
    }

    /// Create a new face from a closure that returns a raw [`Blob`](struct.Blob.html) of table
    pub fn from_table_func<'b, F>(func: F) -> HbBox<Face<'b>>
    where
        F: 'b + Send + Sync + FnMut(Tag) -> Option<HbArc<Blob<'b>>>,
    {
        extern "C" fn destroy_box<U>(ptr: *mut c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }
        extern "C" fn table_func<'b, F>(
            _: *mut hb::hb_face_t,
            tag: hb::hb_tag_t,
            user_data: *mut c_void,
        ) -> *mut hb::hb_blob_t
        where
            F: FnMut(Tag) -> Option<HbArc<Blob<'b>>>,
        {
            let tag = Tag(tag);
            let closure = unsafe { &mut *(user_data as *mut F) };
            let blob = closure(tag);
            match blob {
                Some(blob) => HbArc::into_raw(blob),
                None => std::ptr::null_mut(),
            }
        }
        let boxed_closure = Box::new(func);
        unsafe {
            let face = hb::hb_face_create_for_tables(
                Some(table_func::<'b, F>),
                Box::into_raw(boxed_closure) as *mut _,
                Some(destroy_box::<F>),
            );
            HbBox::from_raw(face)
        }
    }

    //    /// Create a `Font` of this face. By default this will use harfbuzz' included opentype
    // font
    //    /// funcs for shaping and have no scale value set so that the returned values will be in
    // font
    //    /// space.
    //    pub fn create_font(self) -> HbBox<Font<'a>> {
    //        Font::new(self)
    //    }

    pub fn face_data(&self) -> &'a [u8] {
        unsafe {
            let raw_blob = hb::hb_face_reference_blob(self.as_raw());
            Blob::from_raw(raw_blob).get_data()
        }
    }

    pub fn table_with_tag(&self, tag: Tag) -> Option<&[u8]> {
        unsafe {
            let raw_blob = hb::hb_face_reference_table(self.as_raw(), tag.0);
            if raw_blob.is_null() {
                None
            } else {
                let blob = Blob::from_raw(raw_blob);
                if blob.is_empty() {
                    None
                } else {
                    Some(blob.get_data())
                }
            }
        }
    }

    pub fn index(&self) -> u32 {
        unsafe { hb::hb_face_get_index(self.as_raw()) }
    }

    pub fn set_upem(&mut self, upem: u32) {
        unsafe { hb::hb_face_set_upem(self.as_raw(), upem) };
    }

    pub fn upem(&self) -> u32 {
        unsafe { hb::hb_face_get_upem(self.as_raw()) }
    }

    pub fn set_glyph_count(&mut self, count: u32) {
        unsafe { hb::hb_face_set_glyph_count(self.as_raw(), count) };
    }

    pub fn glyph_count(&self) -> u32 {
        unsafe { hb::hb_face_get_glyph_count(self.as_raw()) }
    }
}

impl<'a> HarfbuzzObject for Face<'a> {
    type Raw = hb::hb_face_t;

    unsafe fn reference(&self) {
        hb::hb_face_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_face_destroy(self.as_raw());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use common::Tag;

    #[test]
    fn test_face_from_table_func() {
        let face = Face::from_table_func(|table_tag| {
            let content = format!("{}-table", table_tag);
            Some(content.into_bytes().into())
        });

        let maxp_table = face.table_with_tag(Tag::new('m', 'a', 'x', 'p')).unwrap();
        assert_eq!(maxp_table, b"maxp-table");

        let maxp_table = face.table_with_tag(Tag::new('h', 'h', 'e', 'a')).unwrap();
        assert_eq!(maxp_table, b"hhea-table");
    }
}
<|endoftext|>


<commit_before>
use render::TextureRegion;
use image::{RgbaImage, Rgba};
use {HashMap, load_file_contents};

use std::path::PathBuf;

use std::io;

use std::ops::Range;

use rusttype::{FontCollection, Scale, point};

use std::fmt;

#[derive(Debug, Clone)]
pub struct FontDirectory {
    pub path: PathBuf,
}

impl FontDirectory {
  	pub fn for_path(path:&str) -> FontDirectory {
        FontDirectory {
            path: PathBuf::from(path) // convert to absolute here?
        }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct FontDescription {
	pub family: String,
	pub point_size: u32, // what about, what code points do you want ... and what
}

#[derive(Debug)]
pub struct BitmapGlyph {
	pub texture_region: TextureRegion,
	pub advance: i32, // I think advance should always be u32 ... right?!
}

pub struct LoadedBitmapFont {
	pub image: RgbaImage,
	pub font: BitmapFont,
}

pub struct BitmapFont {
	pub description: FontDescription,
	pub glyphs: HashMap<char, BitmapGlyph>,
	pub kerning: HashMap<(char, char), i32>,
}

impl fmt::Debug for BitmapFont {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "BitmapFont {{ description: {:?} glyphs: {:?} kerning: {:?} }}", self.description, self.glyphs, self.kerning)
    }
}

#[derive(Debug)]
pub enum FontLoadError {
	CouldntLoadFile(PathBuf, io::Error),
	CouldntReadAsFont(PathBuf),
	What,
}

pub fn build_font(resource_path: &str, font_description: &FontDescription, image_size: u32) -> Result<LoadedBitmapFont, FontLoadError> {
    let full_path = PathBuf::from(format!("{}/{}.{}", resource_path, font_description.family, "ttf"));
    println!("full_path -> {:?}", full_path);
    let font_data = load_file_contents(&full_path).map_err(|io| FontLoadError::CouldntLoadFile(full_path.clone(), io))?;
	let collection = FontCollection::from_bytes(&font_data[..]);
	let font = collection.into_font().ok_or(FontLoadError::CouldntReadAsFont(full_path.clone()))?; // this is an option

	let scale = Scale { x: font_description.point_size as f32, y: font_description.point_size as f32 };
    let pixel_height = scale.y.ceil() as i32;

    println!("pixel height {:?}", pixel_height);

    let v_metrics = font.v_metrics(scale);

    let offset = point(0.0, v_metrics.ascent);

    let line_height = v_metrics.ascent - v_metrics.descent + v_metrics.line_gap;

    println!("line height -> {:?}", line_height);

    let char_range : Range<u8> = (32)..(127); // from space to tilde
    let chars : Vec<char> = char_range.map(|n| n as char).collect();

    // println!("mah chars -> {:?}", chars);

	let padding : i32 = 2; // to avoid texture bleeding

	let mut img = RgbaImage::from_pixel(image_size, image_size, Rgba { data: [255,255,255,0] }); // transparent white

	// top left write location of the next glyph
	let mut write_x : i32 = padding;
    let mut write_y : i32 = padding;

    let mut glyphs : HashMap<char, BitmapGlyph> = HashMap::default();

	for &c in &chars {
		if let Some(glyph) = font.glyph(c) {
			let scaled = glyph.scaled(scale);
			let h_metrics = scaled.h_metrics();

			let positioned = scaled.positioned(offset);

			if let Some(bb) = positioned.pixel_bounding_box() {
				if bb.width() + write_x > image_size as i32 {
					write_x = padding;
					write_y += pixel_height + padding;
				}

				write_x -= bb.min.x;

	    		positioned.draw(|x, y, v| {
	                let c = (v * 255.0) as u8;
	                let x = (x as i32 + bb.min.x + write_x) as u32;
	                let y = (y as i32 + bb.min.y + write_y) as u32;
	                // img.put_pixel(x, y, Rgba { data: [c,c,c,255] });
	                img.put_pixel(x, y, Rgba { data: [255,255,255, c] });
	            });

	            // write_x += (h_metrics.advance_width.ceil() as i32) + 1;

	            // let bearing = bb.min.x as i32;
	            let advance = h_metrics.advance_width.ceil() as i32;

	            let bitmap_glyph = BitmapGlyph {
					texture_region: TextureRegion {
						// u_min: (bb.min.x + write_x) as u32,
					 //    u_max: (bb.max.x + write_x) as u32,
					 //    v_min: (bb.min.y + write_y) as u32,
					 //    v_max: (bb.max.y + write_y) as u32,
					 	u_min: (write_x + bb.min.x - 1) as u32,
				    	u_max: (write_x + bb.max.x + 1) as u32,
				    	v_min: (write_y) as u32,
				    	v_max: (write_y + pixel_height) as u32,
				    	texture_size: image_size,
					},
					advance: advance,
				};
				// debug marks
				// {
				// 	let tr = &bitmap_glyph.texture_region;
				// 	img.put_pixel(tr.u_min, tr.v_min, Rgba { data: [255, 0, 0,255]});
				// 	img.put_pixel(tr.u_max - 1, tr.v_min, Rgba { data: [0, 255, 0,255]});
				// 	img.put_pixel(tr.u_min, tr.v_max - 1, Rgba { data: [0, 0, 255,255]});
				// 	img.put_pixel(tr.u_max - 1, tr.v_max - 1, Rgba { data: [255, 105, 180,255]});
				// }

				glyphs.insert(c, bitmap_glyph);
				write_x += (bb.max.x + padding) as i32;
				// println!("{:?} ->  h_metrics are {:?} and bb is {:?} bearing {:?} advance {:?}", c, h_metrics, bb, bearing, advance);
	    	}
		} else {
			println!("wtf, no glyph for '{:?}'", c);
		}
    }

	let mut kerning_map : HashMap<(char, char), i32> = HashMap::default();

	for &from in &chars {
    	for &to in &chars {
    		let kerning = font.pair_kerning(scale, from, to);
    		let kerning_i : i32 = kerning.round() as i32;
    		if kerning_i != 0 {
    			kerning_map.insert((from,to), kerning_i);
    		}
    	}
	}

    Ok(LoadedBitmapFont {
		image: img,
		font: BitmapFont {
			description: font_description.clone(),
			glyphs: glyphs,
			kerning: kerning_map,
		}
	})
}<commit_msg>Removed debug println<commit_after>
use render::TextureRegion;
use image::{RgbaImage, Rgba};
use {HashMap, load_file_contents};

use std::path::PathBuf;

use std::io;

use std::ops::Range;

use rusttype::{FontCollection, Scale, point};

use std::fmt;

#[derive(Debug, Clone)]
pub struct FontDirectory {
    pub path: PathBuf,
}

impl FontDirectory {
  	pub fn for_path(path:&str) -> FontDirectory {
        FontDirectory {
            path: PathBuf::from(path) // convert to absolute here?
        }
    }
}

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct FontDescription {
	pub family: String,
	pub point_size: u32, // what about, what code points do you want ... and what
}

#[derive(Debug)]
pub struct BitmapGlyph {
	pub texture_region: TextureRegion,
	pub advance: i32, // I think advance should always be u32 ... right?!
}

pub struct LoadedBitmapFont {
	pub image: RgbaImage,
	pub font: BitmapFont,
}

pub struct BitmapFont {
	pub description: FontDescription,
	pub glyphs: HashMap<char, BitmapGlyph>,
	pub kerning: HashMap<(char, char), i32>,
}

impl fmt::Debug for BitmapFont {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "BitmapFont {{ description: {:?} glyphs: {:?} kerning: {:?} }}", self.description, self.glyphs, self.kerning)
    }
}

#[derive(Debug)]
pub enum FontLoadError {
	CouldntLoadFile(PathBuf, io::Error),
	CouldntReadAsFont(PathBuf),
	What,
}

pub fn build_font(resource_path: &str, font_description: &FontDescription, image_size: u32) -> Result<LoadedBitmapFont, FontLoadError> {
    let full_path = PathBuf::from(format!("{}/{}.{}", resource_path, font_description.family, "ttf"));
    // println!("full_path -> {:?}", full_path);
    let font_data = load_file_contents(&full_path).map_err(|io| FontLoadError::CouldntLoadFile(full_path.clone(), io))?;
	let collection = FontCollection::from_bytes(&font_data[..]);
	let font = collection.into_font().ok_or(FontLoadError::CouldntReadAsFont(full_path.clone()))?; // this is an option

	let scale = Scale { x: font_description.point_size as f32, y: font_description.point_size as f32 };
    let pixel_height = scale.y.ceil() as i32;

    // println!("pixel height {:?}", pixel_height);

    let v_metrics = font.v_metrics(scale);

    let offset = point(0.0, v_metrics.ascent);

    let line_height = v_metrics.ascent - v_metrics.descent + v_metrics.line_gap;

    // println!("line height -> {:?}", line_height);

    let char_range : Range<u8> = (32)..(127); // from space to tilde
    let chars : Vec<char> = char_range.map(|n| n as char).collect();

    // println!("mah chars -> {:?}", chars);

	let padding : i32 = 2; // to avoid texture bleeding

	let mut img = RgbaImage::from_pixel(image_size, image_size, Rgba { data: [255,255,255,0] }); // transparent white

	// top left write location of the next glyph
	let mut write_x : i32 = padding;
    let mut write_y : i32 = padding;

    let mut glyphs : HashMap<char, BitmapGlyph> = HashMap::default();

	for &c in &chars {
		if let Some(glyph) = font.glyph(c) {
			let scaled = glyph.scaled(scale);
			let h_metrics = scaled.h_metrics();

			let positioned = scaled.positioned(offset);

			if let Some(bb) = positioned.pixel_bounding_box() {
				if bb.width() + write_x > image_size as i32 {
					write_x = padding;
					write_y += pixel_height + padding;
				}

				write_x -= bb.min.x;

	    		positioned.draw(|x, y, v| {
	                let c = (v * 255.0) as u8;
	                let x = (x as i32 + bb.min.x + write_x) as u32;
	                let y = (y as i32 + bb.min.y + write_y) as u32;
	                // img.put_pixel(x, y, Rgba { data: [c,c,c,255] });
	                img.put_pixel(x, y, Rgba { data: [255,255,255, c] });
	            });

	            // write_x += (h_metrics.advance_width.ceil() as i32) + 1;

	            // let bearing = bb.min.x as i32;
	            let advance = h_metrics.advance_width.ceil() as i32;

	            let bitmap_glyph = BitmapGlyph {
					texture_region: TextureRegion {
						// u_min: (bb.min.x + write_x) as u32,
					 //    u_max: (bb.max.x + write_x) as u32,
					 //    v_min: (bb.min.y + write_y) as u32,
					 //    v_max: (bb.max.y + write_y) as u32,
					 	u_min: (write_x + bb.min.x - 1) as u32,
				    	u_max: (write_x + bb.max.x + 1) as u32,
				    	v_min: (write_y) as u32,
				    	v_max: (write_y + pixel_height) as u32,
				    	texture_size: image_size,
					},
					advance: advance,
				};
				// debug marks
				// {
				// 	let tr = &bitmap_glyph.texture_region;
				// 	img.put_pixel(tr.u_min, tr.v_min, Rgba { data: [255, 0, 0,255]});
				// 	img.put_pixel(tr.u_max - 1, tr.v_min, Rgba { data: [0, 255, 0,255]});
				// 	img.put_pixel(tr.u_min, tr.v_max - 1, Rgba { data: [0, 0, 255,255]});
				// 	img.put_pixel(tr.u_max - 1, tr.v_max - 1, Rgba { data: [255, 105, 180,255]});
				// }

				glyphs.insert(c, bitmap_glyph);
				write_x += (bb.max.x + padding) as i32;
				// println!("{:?} ->  h_metrics are {:?} and bb is {:?} bearing {:?} advance {:?}", c, h_metrics, bb, bearing, advance);
	    	}
		} else {
			println!("wtf, no glyph for '{:?}'", c);
		}
    }

	let mut kerning_map : HashMap<(char, char), i32> = HashMap::default();

	for &from in &chars {
    	for &to in &chars {
    		let kerning = font.pair_kerning(scale, from, to);
    		let kerning_i : i32 = kerning.round() as i32;
    		if kerning_i != 0 {
    			kerning_map.insert((from,to), kerning_i);
    		}
    	}
	}

    Ok(LoadedBitmapFont {
		image: img,
		font: BitmapFont {
			description: font_description.clone(),
			glyphs: glyphs,
			kerning: kerning_map,
		}
	})
}<|endoftext|>