<commit_before>use std::io;

use futures::{Future, Poll};

use {AsyncRead, AsyncWrite};

/// A future which will copy all data from a reader into a writer.
/// A modified version of tokio_io::copy::Copy.
///
/// Created by the [`copy`] function, this future will resolve to the number of
/// bytes copied or an error if one happens.
///
/// [`copy`]: fn.copy.html
#[derive(Debug)]
pub struct Copy<R, W> {
    reader: Option<R>,
    read_done: bool,
    writer: Option<W>,
    pos: usize,
    cap: usize,
    amt: u64,
    buf: Box<[u8]>,
}

/// Creates a future which represents copying all the bytes from one object to
/// another.
///
/// The returned future will copy all the bytes read from `reader` into the
/// `writer` specified. This future will only complete once the `reader` has hit
/// EOF and all bytes have been written to and flushed from the `writer`
/// provided.
///
/// On success the number of bytes is returned and the `reader` and `writer` are
/// consumed. On error the error is returned and the I/O objects are consumed as
/// well.
///
/// Unlike original tokio_io::copy::copy, it does not stop on zero length reads
/// , handles BrokenPipe error kind as EOF and flushes after every write
pub fn copy<R, W>(reader: R, writer: W) -> Copy<R, W>
    where R: AsyncRead,
          W: AsyncWrite,
{
    Copy {
        reader: Some(reader),
        read_done: false,
        writer: Some(writer),
        amt: 0,
        pos: 0,
        cap: 0,
        buf: Box::new([0; 2048]),
    }
}

impl<R, W> Future for Copy<R, W>
    where R: AsyncRead,
          W: AsyncWrite,
{
    type Item = (u64, R, W);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<(u64, R, W), io::Error> {
        loop {
            // If our buffer is empty, then we need to read some data to
            // continue.
            if self.pos == self.cap && !self.read_done {
                let reader = self.reader.as_mut().unwrap();
                let rr = reader.read(&mut self.buf);
                if let Err(ref e) = rr {
                    if e.kind() == io::ErrorKind::BrokenPipe {
                        self.read_done = true;
                        continue;
                    }
                }
                let n = try_nb!(rr);
                if n == 0 {
                    continue;
                } else {
                    self.pos = 0;
                    self.cap = n;
                }
            }

            // If our buffer has some data, let's write it out!
            while self.pos < self.cap {
                let writer = self.writer.as_mut().unwrap();
                let i = try_nb!(writer.write(&self.buf[self.pos..self.cap]));
                if i == 0 {
                    return Err(io::Error::new(io::ErrorKind::WriteZero,
                                              "write zero byte into writer"));
                } else {
                    self.pos += i;
                    self.amt += i as u64;
                }
                try_nb!(writer.flush());
            }

            // If we've written al the data and we've seen EOF, flush out the
            // data and finish the transfer.
            // done with the entire transfer.
            if self.pos == self.cap && self.read_done {
                try_nb!(self.writer.as_mut().unwrap().flush());
                let reader = self.reader.take().unwrap();
                let writer = self.writer.take().unwrap();
                return Ok((self.amt, reader, writer).into())
            }
        }
    }
}

<commit_msg>Minor performance tune<commit_after>use std::io;

use futures::{Future, Poll};

use {AsyncRead, AsyncWrite};

/// A future which will copy all data from a reader into a writer.
/// A modified version of tokio_io::copy::Copy.
///
/// Created by the [`copy`] function, this future will resolve to the number of
/// bytes copied or an error if one happens.
///
/// [`copy`]: fn.copy.html
#[derive(Debug)]
pub struct Copy<R, W> {
    reader: Option<R>,
    read_done: bool,
    writer: Option<W>,
    pos: usize,
    cap: usize,
    amt: u64,
    buf: Box<[u8]>,
}

/// Creates a future which represents copying all the bytes from one object to
/// another.
///
/// The returned future will copy all the bytes read from `reader` into the
/// `writer` specified. This future will only complete once the `reader` has hit
/// EOF and all bytes have been written to and flushed from the `writer`
/// provided.
///
/// On success the number of bytes is returned and the `reader` and `writer` are
/// consumed. On error the error is returned and the I/O objects are consumed as
/// well.
///
/// Unlike original tokio_io::copy::copy, it does not stop on zero length reads
/// , handles BrokenPipe error kind as EOF and flushes after every write
pub fn copy<R, W>(reader: R, writer: W) -> Copy<R, W>
    where R: AsyncRead,
          W: AsyncWrite,
{
    Copy {
        reader: Some(reader),
        read_done: false,
        writer: Some(writer),
        amt: 0,
        pos: 0,
        cap: 0,
        buf: Box::new([0; 8192]),
    }
}

impl<R, W> Future for Copy<R, W>
    where R: AsyncRead,
          W: AsyncWrite,
{
    type Item = (u64, R, W);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<(u64, R, W), io::Error> {
        loop {
            // If our buffer is empty, then we need to read some data to
            // continue.
            if self.pos == self.cap && !self.read_done {
                let reader = self.reader.as_mut().unwrap();
                let rr = reader.read(&mut self.buf);
                if let Err(ref e) = rr {
                    if e.kind() == io::ErrorKind::BrokenPipe {
                        self.read_done = true;
                        continue;
                    }
                }
                let n = try_nb!(rr);
                if n == 0 {
                    continue;
                } else {
                    self.pos = 0;
                    self.cap = n;
                }
            }

            // If our buffer has some data, let's write it out!
            while self.pos < self.cap {
                let writer = self.writer.as_mut().unwrap();
                let i = try_nb!(writer.write(&self.buf[self.pos..self.cap]));
                if i == 0 {
                    return Err(io::Error::new(io::ErrorKind::WriteZero,
                                              "write zero byte into writer"));
                } else {
                    self.pos += i;
                    self.amt += i as u64;
                }
                try_nb!(writer.flush());
            }

            // If we've written al the data and we've seen EOF, flush out the
            // data and finish the transfer.
            // done with the entire transfer.
            if self.pos == self.cap && self.read_done {
                try_nb!(self.writer.as_mut().unwrap().flush());
                let reader = self.reader.take().unwrap();
                let writer = self.writer.take().unwrap();
                return Ok((self.amt, reader, writer).into())
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::io::{TempDir, MemWriter};
use std::str::from_utf8;
use sync::{Arc, Mutex, RWLock};
use collections::hashmap::HashMap;
use schema;
use buffer;

#[deriving(Show, Eq, TotalEq, Hash, Clone)]
struct Register {
	record: schema::Record,
	datatype: schema::SqlType,
}

impl Register {
	fn new(rec: schema::Record, typ: schema::SqlType) -> Register {
		Register {
			record: rec,
			datatype: typ,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str<'a>(&'a self) -> &'a str {
		let d = self.record.get_data();
		from_utf8(d).unwrap()
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan {
	relation: schema::Relation,
	segment: Arc<Mutex<schema::SPSegment>>,
	current: uint,
}

impl TableScan {
	fn new(rel: schema::Relation, seg: Arc<Mutex<schema::SPSegment>>) -> TableScan {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl Operatorish<Vec<Register>> for TableScan {
}

impl Iterator<Vec<Register>> for TableScan {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let mut seg = self.segment.lock();
			let tup = self.relation.get(seg.deref_mut(), self.current);
			let mut res = tup.move_iter().map(|(v, t)| Register::new(v, t)).
				collect::<Vec<Register>>();
			debug!("TS: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<'a, T, V> {
	input: T,
	output: &'a mut V,
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Print<'a, T, V> {
	fn new(input: T, output: &'a mut V) -> Print<'a, T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Iterator<Vec<Register>> for Print<'a, T, V> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			Some(reg) => {
				for item in reg.iter() {
					match item.datatype {
						schema::Varchar(_) => self.output.write(item.get_str().as_bytes()),
						schema::Integer => self.output.write(
							format!("{}", item.get_int()).as_bytes())
					};
					self.output.write(", ".as_bytes());
				}
				self.output.write("\n".as_bytes());
				Some(reg)
			},
			None => None,
		}
	}
}

struct Project<T> {
	input: T,
	registerids: Vec<uint>,
}

impl<T: Operatorish<Vec<Register>>> Project<T> {
	fn new(input: T, regs: Vec<uint>) -> Project<T> {
		Project {
			input: input,
			registerids: regs,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Project<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			None => None,
			Some(mut reg) => {
				let mut res = Vec::with_capacity(self.registerids.len());
				let mut regids = self.registerids.clone();
				regids.reverse();
				for index in regids.move_iter() {
					let value = reg.remove(index);
					let v = match value {
						None => fail!("Projection doesn't have vield {}", index),
						Some(v) => v,
					};
					res.push(v);
				}
				Some(res)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Project<T> {
}

#[deriving(Show)]
enum Selectable {
	Varchar(~str),
	Integer(int),
}

struct Select<T> {
	input: T,
	index: uint,
	value: Selectable,
}

impl<T: Operatorish<Vec<Register>>> Select<T> {
	fn new(input: T, index: uint, value: Selectable) -> Select<T> {
		Select {
			input: input,
			index: index,
			value: value,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Select<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		// initial value
		let mut cur = self.input.next();
		while cur.is_some() {
			// we made sure cur is Some(…), so we can unwrap safely
			let reg = cur.unwrap();

			// check what we got to select for and retrieve values
			// accordingly
			match self.value {
				// comparing to a string
				Varchar(ref v) => {
					println!("Comparing {} with {}",
						reg.get(self.index).get_str(),
						v);
					// getting the register value as string
					if reg.get(self.index).get_str() == *v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				},
				// comparing to a number
				Integer(v) => {
					// compare against reg as integer
					if reg.get(self.index).get_int() == v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				}
			}
		}
		// no more entries, signal iterator exhaustion
		None
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Select<T> {
}

struct HashJoin<T> {
	result: Vec<(Vec<Register>, Vec<Register>)>,
}

impl<T: Operatorish<Vec<Register>>> HashJoin<T> {
	fn new(mut left: T, mut right: T, on: (uint, uint)) -> HashJoin<T> {
		let mut map = HashMap::new();
		let (lindex, rindex) = on;
		for mut tuple in left {
			let element = tuple.get(lindex).clone();
			map.insert(element, tuple);
		}

		debug!("HashJoin map: {}", map);
		let mut res = Vec::new();
		for r in right {
			let element = r.get(rindex).clone();
			match map.find_copy(&element) {
				Some(s) => res.push((s, r)),
				None => continue,
			};
		}
		debug!("HashJon result: {}", res);

		HashJoin {
			result: res,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for HashJoin<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		match self.result.shift() {
			None => None,
			Some((mut s, r)) => {
				s.push_all_move(r);
				Some(s)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for HashJoin<T> {
}

fn construct_relation(prefix: ~str) -> (schema::Relation, Arc<Mutex<schema::SPSegment>>) {
	let dir = match TempDir::new(prefix) {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment::new(1, Arc::new(RWLock::new(manager)));

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));
	let segmut = Arc::new(Mutex::new(seg));
	(relation, segmut)
}

#[test]
fn simple_tablescan() {
	let (relation, segmut) = construct_relation(~"tablescan");

	let mut ts = TableScan::new(relation, segmut);
	let mut result = Vec::new();
	let expected = vec!((~"Alice", 20), (~"Bob", 40));
	for tuple in ts {
		println!("Got entry {}", tuple);
		let n = tuple.get(0).get_str().to_owned();
		let i = tuple.get(1).get_int();
		result.push((n, i));
	}
	assert_eq!(expected, result);
}

#[test]
fn simple_print() {
	let (relation, segmut) = construct_relation(~"print");
	let mut mw = MemWriter::new();
	{
		let mut ts = TableScan::new(relation.clone(), segmut.clone());
		let mut pr = Print::new(ts, &mut mw);
		// force write by iterating, strange API
		for _ in pr {}
	}
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();
	let expected = ~"Alice, 20, \nBob, 40, \n";

	println!("Printed:\n{}", printed);
	assert_eq!(expected, printed);
}

#[test]
fn simple_project() {
	let (relation, segmut) = construct_relation(~"project");
	let mut mw = MemWriter::new();
	{
		let mut ts = TableScan::new(relation, segmut);
		let mut pr = Project::new(ts, vec!(0));
		let mut pr = Print::new(pr, &mut mw);
		for _ in pr {}
	}
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();
	let expected = ~"Alice, \nBob, \n";

	println!("Printed:\n{}", printed);
	assert_eq!(expected, printed);
}

#[test]
fn simple_select() {
	let (relation, segmut) = construct_relation(~"select");
	let mut mw = MemWriter::new();
	{
		let mut ts = TableScan::new(relation.clone(), segmut.clone());
		let mut se = Select::new(ts, 1, Integer(20));
		let mut pr = Print::new(se, &mut mw);
		for _ in pr {}
	}
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();
	let expected = ~"Alice, 20, \n";

	println!("Printed:\n{}", printed);
	assert_eq!(expected, printed);

	let mut mw = MemWriter::new();
	{
		let mut ts = TableScan::new(relation.clone(), segmut.clone());
		let mut se = Select::new(ts, 0, Varchar(~"Bob"));
		let mut pr = Print::new(se, &mut mw);
		for _ in pr {}
	}
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();
	let expected = ~"Bob, 40, \n";

	println!("Printed:\n{}", printed);
	assert_eq!(expected, printed);
}

#[test]
fn simple_hashjoin() {
	let dir = match TempDir::new("hashjoin") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment::new(1, Arc::new(RWLock::new(manager)));

	/* first relation */
	let mut people = schema::Relation::new(~"Person");
	let id = schema::Column::new(~"id", schema::Integer, vec!(schema::NotNull));
	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	people.add_column(id);
	people.add_column(name);
	people.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Alice")));
	people.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"Bob")));
	people.insert(&mut seg, vec!(schema::Record::from_int(2), schema::Record::from_str(~"Eve")));
	people.insert(&mut seg, vec!(schema::Record::from_int(3), schema::Record::from_str(~"Mallory")));

	/* second relation */
	let mut oses = schema::Relation::new(~"OSes");
	let ident = schema::Column::new(~"ident", schema::Integer, vec!(schema::NotNull));
	let os = schema::Column::new(~"OS", schema::Varchar(128), vec!(schema::NotNull));
	oses.add_column(ident);
	oses.add_column(os);
	oses.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Plan 9")));
	oses.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"NetBSD")));
	oses.insert(&mut seg, vec!(schema::Record::from_int(3), schema::Record::from_str(~"GNU/Linux")));

	let mut mw = MemWriter::new();
	let segmut = Arc::new(Mutex::new(seg));
	let ts_left = TableScan::new(oses, segmut.clone());
	let ts_right = TableScan::new(people, segmut.clone());
	let hj = HashJoin::new(ts_left, ts_right, (0,0));
	{
		let mut pr = Print::new(hj, &mut mw);
		for _ in pr {}
	}
	let expected = ~"0, Plan 9, 0, Alice, \n1, NetBSD, 1, Bob, \n3, GNU/Linux, 3, Mallory, \n";
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();

	assert_eq!(expected, printed);
}
<commit_msg>Removing mutability flags where not useful<commit_after>use std::io::{TempDir, MemWriter};
use std::str::from_utf8;
use sync::{Arc, Mutex, RWLock};
use collections::hashmap::HashMap;
use schema;
use buffer;

#[deriving(Show, Eq, TotalEq, Hash, Clone)]
struct Register {
	record: schema::Record,
	datatype: schema::SqlType,
}

impl Register {
	fn new(rec: schema::Record, typ: schema::SqlType) -> Register {
		Register {
			record: rec,
			datatype: typ,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str<'a>(&'a self) -> &'a str {
		let d = self.record.get_data();
		from_utf8(d).unwrap()
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan {
	relation: schema::Relation,
	segment: Arc<Mutex<schema::SPSegment>>,
	current: uint,
}

impl TableScan {
	fn new(rel: schema::Relation, seg: Arc<Mutex<schema::SPSegment>>) -> TableScan {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl Operatorish<Vec<Register>> for TableScan {
}

impl Iterator<Vec<Register>> for TableScan {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let mut seg = self.segment.lock();
			let tup = self.relation.get(seg.deref_mut(), self.current);
			let res = tup.move_iter().map(|(v, t)| Register::new(v, t)).
				collect::<Vec<Register>>();
			debug!("TS: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<'a, T, V> {
	input: T,
	output: &'a mut V,
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Print<'a, T, V> {
	fn new(input: T, output: &'a mut V) -> Print<'a, T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Iterator<Vec<Register>> for Print<'a, T, V> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			Some(reg) => {
				for item in reg.iter() {
					match item.datatype {
						schema::Varchar(_) => self.output.write(item.get_str().as_bytes()),
						schema::Integer => self.output.write(
							format!("{}", item.get_int()).as_bytes())
					};
					self.output.write(", ".as_bytes());
				}
				self.output.write("\n".as_bytes());
				Some(reg)
			},
			None => None,
		}
	}
}

struct Project<T> {
	input: T,
	registerids: Vec<uint>,
}

impl<T: Operatorish<Vec<Register>>> Project<T> {
	fn new(input: T, regs: Vec<uint>) -> Project<T> {
		Project {
			input: input,
			registerids: regs,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Project<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			None => None,
			Some(mut reg) => {
				let mut res = Vec::with_capacity(self.registerids.len());
				let mut regids = self.registerids.clone();
				regids.reverse();
				for index in regids.move_iter() {
					let value = reg.remove(index);
					let v = match value {
						None => fail!("Projection doesn't have vield {}", index),
						Some(v) => v,
					};
					res.push(v);
				}
				Some(res)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Project<T> {
}

#[deriving(Show)]
enum Selectable {
	Varchar(~str),
	Integer(int),
}

struct Select<T> {
	input: T,
	index: uint,
	value: Selectable,
}

impl<T: Operatorish<Vec<Register>>> Select<T> {
	fn new(input: T, index: uint, value: Selectable) -> Select<T> {
		Select {
			input: input,
			index: index,
			value: value,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Select<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		// initial value
		let mut cur = self.input.next();
		while cur.is_some() {
			// we made sure cur is Some(…), so we can unwrap safely
			let reg = cur.unwrap();

			// check what we got to select for and retrieve values
			// accordingly
			match self.value {
				// comparing to a string
				Varchar(ref v) => {
					println!("Comparing {} with {}",
						reg.get(self.index).get_str(),
						v);
					// getting the register value as string
					if reg.get(self.index).get_str() == *v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				},
				// comparing to a number
				Integer(v) => {
					// compare against reg as integer
					if reg.get(self.index).get_int() == v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				}
			}
		}
		// no more entries, signal iterator exhaustion
		None
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Select<T> {
}

struct HashJoin<T> {
	result: Vec<(Vec<Register>, Vec<Register>)>,
}

impl<T: Operatorish<Vec<Register>>> HashJoin<T> {
	fn new(mut left: T, mut right: T, on: (uint, uint)) -> HashJoin<T> {
		let mut map = HashMap::new();
		let (lindex, rindex) = on;
		for tuple in left {
			let element = tuple.get(lindex).clone();
			map.insert(element, tuple);
		}

		debug!("HashJoin map: {}", map);
		let mut res = Vec::new();
		for r in right {
			let element = r.get(rindex).clone();
			match map.find_copy(&element) {
				Some(s) => res.push((s, r)),
				None => continue,
			};
		}
		debug!("HashJon result: {}", res);

		HashJoin {
			result: res,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for HashJoin<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		match self.result.shift() {
			None => None,
			Some((mut s, r)) => {
				s.push_all_move(r);
				Some(s)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for HashJoin<T> {
}

fn construct_relation(prefix: ~str) -> (schema::Relation, Arc<Mutex<schema::SPSegment>>) {
	let dir = match TempDir::new(prefix) {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment::new(1, Arc::new(RWLock::new(manager)));

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));
	let segmut = Arc::new(Mutex::new(seg));
	(relation, segmut)
}

#[test]
fn simple_tablescan() {
	let (relation, segmut) = construct_relation(~"tablescan");

	let mut ts = TableScan::new(relation, segmut);
	let mut result = Vec::new();
	let expected = vec!((~"Alice", 20), (~"Bob", 40));
	for tuple in ts {
		println!("Got entry {}", tuple);
		let n = tuple.get(0).get_str().to_owned();
		let i = tuple.get(1).get_int();
		result.push((n, i));
	}
	assert_eq!(expected, result);
}

#[test]
fn simple_print() {
	let (relation, segmut) = construct_relation(~"print");
	let mut mw = MemWriter::new();
	{
		let ts = TableScan::new(relation.clone(), segmut.clone());
		let mut pr = Print::new(ts, &mut mw);
		// force write by iterating, strange API
		for _ in pr {}
	}
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();
	let expected = ~"Alice, 20, \nBob, 40, \n";

	println!("Printed:\n{}", printed);
	assert_eq!(expected, printed);
}

#[test]
fn simple_project() {
	let (relation, segmut) = construct_relation(~"project");
	let mut mw = MemWriter::new();
	{
		let ts = TableScan::new(relation, segmut);
		let pro = Project::new(ts, vec!(0));
		let mut pr = Print::new(pro, &mut mw);
		for _ in pr {}
	}
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();
	let expected = ~"Alice, \nBob, \n";

	println!("Printed:\n{}", printed);
	assert_eq!(expected, printed);
}

#[test]
fn simple_select() {
	let (relation, segmut) = construct_relation(~"select");
	let mut mw = MemWriter::new();
	{
		let ts = TableScan::new(relation.clone(), segmut.clone());
		let se = Select::new(ts, 1, Integer(20));
		let mut pr = Print::new(se, &mut mw);
		for _ in pr {}
	}
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();
	let expected = ~"Alice, 20, \n";

	println!("Printed:\n{}", printed);
	assert_eq!(expected, printed);

	let mut mw = MemWriter::new();
	{
		let ts = TableScan::new(relation.clone(), segmut.clone());
		let se = Select::new(ts, 0, Varchar(~"Bob"));
		let mut pr = Print::new(se, &mut mw);
		for _ in pr {}
	}
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();
	let expected = ~"Bob, 40, \n";

	println!("Printed:\n{}", printed);
	assert_eq!(expected, printed);
}

#[test]
fn simple_hashjoin() {
	let dir = match TempDir::new("hashjoin") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment::new(1, Arc::new(RWLock::new(manager)));

	/* first relation */
	let mut people = schema::Relation::new(~"Person");
	let id = schema::Column::new(~"id", schema::Integer, vec!(schema::NotNull));
	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	people.add_column(id);
	people.add_column(name);
	people.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Alice")));
	people.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"Bob")));
	people.insert(&mut seg, vec!(schema::Record::from_int(2), schema::Record::from_str(~"Eve")));
	people.insert(&mut seg, vec!(schema::Record::from_int(3), schema::Record::from_str(~"Mallory")));

	/* second relation */
	let mut oses = schema::Relation::new(~"OSes");
	let ident = schema::Column::new(~"ident", schema::Integer, vec!(schema::NotNull));
	let os = schema::Column::new(~"OS", schema::Varchar(128), vec!(schema::NotNull));
	oses.add_column(ident);
	oses.add_column(os);
	oses.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Plan 9")));
	oses.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"NetBSD")));
	oses.insert(&mut seg, vec!(schema::Record::from_int(3), schema::Record::from_str(~"GNU/Linux")));

	let mut mw = MemWriter::new();
	let segmut = Arc::new(Mutex::new(seg));
	let ts_left = TableScan::new(oses, segmut.clone());
	let ts_right = TableScan::new(people, segmut.clone());
	let hj = HashJoin::new(ts_left, ts_right, (0,0));
	{
		let mut pr = Print::new(hj, &mut mw);
		for _ in pr {}
	}
	let expected = ~"0, Plan 9, 0, Alice, \n1, NetBSD, 1, Bob, \n3, GNU/Linux, 3, Mallory, \n";
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();

	assert_eq!(expected, printed);
}
<|endoftext|>


<commit_before>//! This module requires the `num-ops` feature and supplies implementations for various types from
//! the `num` crate.

use ops::{Operation, CommutativeOperation, Identity, Inverse};
use ops::{Add, Mul, Xor, And, Or};
use num::{BigInt, BigUint, Complex, Zero, One};
use num::bigint::Sign;
use num::integer::Integer;
use num::rational::Ratio;

use std::mem;
use std::num::Wrapping;

macro_rules! impl_operation_for_add_no_addassign {
    ($t:ty) => {
        impl Operation<$t> for Add {
            fn combine(a: &$t, b: &$t) -> $t {
                a.clone() + b
            }
            fn combine_mut(a: &mut $t, b: &$t) {
                let aa = mem::replace(a, Add::identity());
                *a = aa + b;
            }
            fn combine_mut2(a: &$t, b: &mut $t) {
                let bb = mem::replace(b, Add::identity());
                *b = bb + a;
            }
            fn combine_left(a: $t, b: &$t) -> $t {
                a + b
            }
            fn combine_right(a: &$t, b: $t) -> $t {
                b + a
            }
        }
        impl Inverse<$t> for Add {
            fn uncombine(a: &mut $t, b: &$t) {
                let aa = mem::replace(a, Add::identity());
                *a = aa - b;
            }
        }
    }
}

macro_rules! impl_identity_for_add {
    ($t:ty => $iden:expr) => {
        impl Identity<$t> for Add {
            fn identity() -> $t {
                $iden
            }
        }
    }
}

impl_operation_for_add_no_addassign!(BigInt);
impl_identity_for_add!(BigInt => BigInt::from_slice(Sign::NoSign, &[]));
impl CommutativeOperation<BigInt> for Add {}

impl_operation_for_add_no_addassign!(BigUint);
impl_identity_for_add!(BigUint => BigUint::from_slice(&[]));
impl CommutativeOperation<BigUint> for Add {}

impl<T> Operation<Complex<T>> for Add where Add: Operation<T> {
    fn combine(a: &Complex<T>, b: &Complex<T>) -> Complex<T> {
        Complex {
            re: Add::combine(&a.re, &b.re),
            im: Add::combine(&a.im, &b.im)
        }
    }
    fn combine_mut(a: &mut Complex<T>, b: &Complex<T>) {
        Add::combine_mut(&mut a.re, &b.re);
        Add::combine_mut(&mut a.im, &b.im);
    }
    fn combine_mut2(a: &Complex<T>, b: &mut Complex<T>) {
        Add::combine_mut2(&a.re, &mut b.re);
        Add::combine_mut2(&a.im, &mut b.im);
    }
    fn combine_left(a: Complex<T>, b: &Complex<T>) -> Complex<T> {
        Complex {
            re: Add::combine_left(a.re, &b.re),
            im: Add::combine_left(a.im, &b.im)
        }
    }
    fn combine_right(a: &Complex<T>, b: Complex<T>) -> Complex<T> {
        Complex {
            re: Add::combine_right(&a.re, b.re),
            im: Add::combine_right(&a.im, b.im)
        }
    }
    fn combine_both(a: Complex<T>, b: Complex<T>) -> Complex<T> {
        Complex {
            re: Add::combine_both(a.re, b.re),
            im: Add::combine_both(a.im, b.im)
        }
    }
}
impl<T> CommutativeOperation<Complex<T>> for Add where Add: CommutativeOperation<T> {}
impl<T> Identity<Complex<T>> for Add where Add: Identity<T> {
    fn identity() -> Complex<T> {
        Complex { re: Add::identity(), im: Add::identity() }
    }
}
impl<T> Inverse<Complex<T>> for Add where Add: Inverse<T> {
    fn uncombine(a: &mut Complex<T>, b: &Complex<T>) {
        Add::uncombine(&mut a.re, &b.re);
        Add::uncombine(&mut a.im, &b.im);
    }
}

macro_rules! impl_ratio_op {
    ($op:ty, $add:tt, $sub:tt, $iden:expr) => {
        impl<T: Clone+Integer> Operation<Ratio<T>> for $op {
            fn combine(a: &Ratio<T>, b: &Ratio<T>) -> Ratio<T> {
                a $add b
            }
            fn combine_mut(a: &mut Ratio<T>, b: &Ratio<T>) {
                let aa = mem::replace(a, Add::identity());
                *a = aa $add b;
            }
            fn combine_mut2(a: &Ratio<T>, b: &mut Ratio<T>) {
                let bb = mem::replace(b, Add::identity());
                *b = bb $add a;
            }
            fn combine_left(a: Ratio<T>, b: &Ratio<T>) -> Ratio<T> {
                a $add b
            }
            fn combine_right(a: &Ratio<T>, b: Ratio<T>) -> Ratio<T> {
                b $add a
            }
        }
        impl<T: Clone+Integer> CommutativeOperation<Ratio<T>> for $op {}
        impl<T: Clone+Integer> Identity<Ratio<T>> for $op {
            fn identity() -> Ratio<T> {
                $iden
            }
        }
        impl<T: Clone+Integer> Inverse<Ratio<T>> for $op {
            fn uncombine(a: &mut Ratio<T>, b: &Ratio<T>) {
                let aa = mem::replace(a, Add::identity());
                *a = aa $sub b;
            }
        }
    }
}
impl_ratio_op!(Add, +, -, Ratio::zero());
impl_ratio_op!(Mul, *, /, Ratio::one());

<commit_msg>update num-ops to new ops system<commit_after>//! This module requires the `num-ops` feature and supplies implementations for various types from
//! the `num` crate.

use ops::{Operation, CommutativeOperation, Identity, Inverse};
use ops::{Add, Mul};
use num::{BigInt, BigUint, Complex, Zero, One};
use num::bigint::Sign;
use num::integer::Integer;
use num::rational::Ratio;

use std::mem;

macro_rules! impl_big {
    ($t:ty) => {
        impl Operation<$t> for Add {
            fn combine(&self, a: &$t, b: &$t) -> $t {
                a.clone() + b
            }
            fn combine_mut(&self, a: &mut $t, b: &$t) {
                let aa = mem::replace(a, self.identity());
                *a = aa + b;
            }
            fn combine_mut2(&self, a: &$t, b: &mut $t) {
                let bb = mem::replace(b, self.identity());
                *b = bb + a;
            }
            fn combine_left(&self, a: $t, b: &$t) -> $t {
                a + b
            }
            fn combine_right(&self, a: &$t, b: $t) -> $t {
                b + a
            }
        }
        impl Operation<$t> for Mul {
            fn combine(&self, a: &$t, b: &$t) -> $t {
                a.clone() * b
            }
            fn combine_mut(&self, a: &mut $t, b: &$t) {
                let aa = mem::replace(a, self.identity());
                *a = aa * b;
            }
            fn combine_mut2(&self, a: &$t, b: &mut $t) {
                let bb = mem::replace(b, self.identity());
                *b = bb * a;
            }
            fn combine_left(&self, a: $t, b: &$t) -> $t {
                a * b
            }
            fn combine_right(&self, a: &$t, b: $t) -> $t {
                b * a
            }
        }
        impl Inverse<$t> for Add {
            fn uncombine(&self, a: &mut $t, b: &$t) {
                let aa = mem::replace(a, self.identity());
                *a = aa - b;
            }
        }
        impl Inverse<$t> for Mul {
            fn uncombine(&self, a: &mut $t, b: &$t) {
                let aa = mem::replace(a, self.identity());
                *a = aa / b;
            }
        }
    }
}

macro_rules! impl_iden_add {
    ($t:ty => $iden:expr) => {
        impl Identity<$t> for Add {
            fn identity(&self) -> $t {
                $iden
            }
        }
    }
}
macro_rules! impl_iden_mul {
    ($t:ty => $iden:expr) => {
        impl Identity<$t> for Mul {
            fn identity(&self) -> $t {
                $iden
            }
        }
    }
}

impl_big!(BigInt);
impl_iden_add!(BigInt => BigInt::from_slice(Sign::NoSign, &[]));
impl_iden_mul!(BigInt => BigInt::from_slice(Sign::Plus, &[1]));
impl CommutativeOperation<BigInt> for Add {}

impl_big!(BigUint);
impl_iden_add!(BigUint => BigUint::from_slice(&[]));
impl_iden_mul!(BigUint => BigUint::from_slice(&[1]));
impl CommutativeOperation<BigUint> for Add {}

impl<T> Operation<Complex<T>> for Add where Add: Operation<T> {
    fn combine(&self, a: &Complex<T>, b: &Complex<T>) -> Complex<T> {
        Complex {
            re: self.combine(&a.re, &b.re),
            im: self.combine(&a.im, &b.im)
        }
    }
    fn combine_mut(&self, a: &mut Complex<T>, b: &Complex<T>) {
        self.combine_mut(&mut a.re, &b.re);
        self.combine_mut(&mut a.im, &b.im);
    }
    fn combine_mut2(&self, a: &Complex<T>, b: &mut Complex<T>) {
        self.combine_mut2(&a.re, &mut b.re);
        self.combine_mut2(&a.im, &mut b.im);
    }
    fn combine_left(&self, a: Complex<T>, b: &Complex<T>) -> Complex<T> {
        Complex {
            re: self.combine_left(a.re, &b.re),
            im: self.combine_left(a.im, &b.im)
        }
    }
    fn combine_right(&self, a: &Complex<T>, b: Complex<T>) -> Complex<T> {
        Complex {
            re: self.combine_right(&a.re, b.re),
            im: self.combine_right(&a.im, b.im)
        }
    }
    fn combine_both(&self, a: Complex<T>, b: Complex<T>) -> Complex<T> {
        Complex {
            re: self.combine_both(a.re, b.re),
            im: self.combine_both(a.im, b.im)
        }
    }
}
impl<T> CommutativeOperation<Complex<T>> for Add where Add: CommutativeOperation<T> {}
impl<T> Identity<Complex<T>> for Add where Add: Identity<T> {
    fn identity(&self) -> Complex<T> {
        Complex { re: self.identity(), im: self.identity() }
    }
}
impl<T> Inverse<Complex<T>> for Add where Add: Inverse<T> {
    fn uncombine(&self, a: &mut Complex<T>, b: &Complex<T>) {
        self.uncombine(&mut a.re, &b.re);
        self.uncombine(&mut a.im, &b.im);
    }
}

macro_rules! impl_ratio_op {
    ($op:ty, $add:tt, $sub:tt, $iden:expr) => {
        impl<T: Clone+Integer> Operation<Ratio<T>> for $op {
            fn combine(&self, a: &Ratio<T>, b: &Ratio<T>) -> Ratio<T> {
                a $add b
            }
            fn combine_mut(&self, a: &mut Ratio<T>, b: &Ratio<T>) {
                let aa = mem::replace(a, self.identity());
                *a = aa $add b;
            }
            fn combine_mut2(&self, a: &Ratio<T>, b: &mut Ratio<T>) {
                let bb = mem::replace(b, self.identity());
                *b = bb $add a;
            }
            fn combine_left(&self, a: Ratio<T>, b: &Ratio<T>) -> Ratio<T> {
                a $add b
            }
            fn combine_right(&self, a: &Ratio<T>, b: Ratio<T>) -> Ratio<T> {
                b $add a
            }
        }
        impl<T: Clone+Integer> CommutativeOperation<Ratio<T>> for $op {}
        impl<T: Clone+Integer> Identity<Ratio<T>> for $op {
            fn identity(&self) -> Ratio<T> {
                $iden
            }
        }
        impl<T: Clone+Integer> Inverse<Ratio<T>> for $op {
            fn uncombine(&self, a: &mut Ratio<T>, b: &Ratio<T>) {
                let aa = mem::replace(a, self.identity());
                *a = aa $sub b;
            }
        }
    }
}
impl_ratio_op!(Add, +, -, Ratio::zero());
impl_ratio_op!(Mul, *, /, Ratio::one());

<|endoftext|>


<commit_before>use prelude::*;
use super::{CheckpointFormat};
use rw::{ReadBuffer, WriteBuffer};

use csv::{Writer as CsvWriter};
use densearray::{Reshape, ReshapeMut};

use rand::{Rng, thread_rng};
use rustc_serialize::{Encodable};
use std::cmp::{max, min};
use std::fmt::{Debug};
use std::fs::{File, create_dir_all};
use std::io::{Write};
use std::path::{Path, PathBuf};
use std::thread::{sleep};
use std::time::{Duration, Instant};

//pub mod adagrad;
pub mod adagrad_new;
//pub mod adam;
pub mod adam_new;
//pub mod rmsprop;
//pub mod sgd;
pub mod sgd_new;
//pub mod shared_sgd;
pub mod shared_sgd_new;

#[derive(Clone, Debug)]
pub struct CheckpointConfig {
  pub prefix:   PathBuf,
  pub trace:    bool,
}

pub struct CheckpointState {
  pub cfg:          CheckpointConfig,
  pub config_file:  Option<File>,
  pub train_file:   Option<CsvWriter<File>>,
  pub valid_file:   Option<CsvWriter<File>>,
  start_time:   Instant,
  lap_time:     Instant,
  elapsed_s:    f64,
}

impl CheckpointState {
  pub fn new(cfg: CheckpointConfig) -> CheckpointState {
    Self::with_fields(cfg, "iter,loss,accuracy,elapsed")
  }

  pub fn with_fields(cfg: CheckpointConfig, fields: &str) -> CheckpointState {
    let delay_ns = thread_rng().gen_range(1_000_000, 100_000_000);
    sleep(Duration::new(0, delay_ns));
    create_dir_all(&cfg.prefix).ok();
    loop {
      let mut lo_idx = Some(0);
      let mut hi_idx = None;
      let mut idx = 0;
      while lo_idx != hi_idx {
        match (lo_idx, hi_idx) {
          (Some(lo), None) => {
            idx = lo;
          }
          (Some(lo), Some(hi)) => {
            idx = (lo + hi) / 2;
          }
          _ => unreachable!(),
        }
        let mut config_path = PathBuf::from(&cfg.prefix);
        let mut config_filename = format!("config.{}", idx);
        config_path.push(&config_filename);
        if config_path.exists() {
          match (lo_idx, hi_idx) {
            (Some(lo), None) => {
              lo_idx = Some(lo + max(1, lo));
            }
            (Some(lo), Some(hi)) => {
              lo_idx = Some(min(hi, max(lo + 1, idx)));
            }
            _ => unreachable!(),
          }
        } else {
          match (lo_idx, hi_idx) {
            (Some(_), None) => {
              lo_idx = Some(idx / 2);
              hi_idx = Some(idx);
            }
            (Some(_), Some(_)) => {
              hi_idx = Some(idx);
            }
            _ => unreachable!(),
          }
        }
      }
      idx = hi_idx.unwrap();
      let mut cfg_f = None;
      let mut trace_f = None;
      let mut valid_f = None;
      let mut config_path = PathBuf::from(&cfg.prefix);
      let mut config_filename = format!("config.{}", idx);
      config_path.push(&config_filename);
      if config_path.exists() {
        continue;
      }
      match File::create(&config_path) {
        Err(_) => {
          continue;
        }
        Ok(f) => {
          cfg_f = Some(f);
        }
      }
      if cfg.trace {
        let mut train_path = PathBuf::from(&cfg.prefix);
        let mut train_filename = format!("train.log.{}", idx);
        train_path.push(&train_filename);
        assert!(!train_path.exists());
        let mut f = File::create(&train_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        trace_f = Some(f);

        let mut valid_path = PathBuf::from(&cfg.prefix);
        let mut valid_filename = format!("valid.log.{}", idx);
        valid_path.push(&valid_filename);
        assert!(!valid_path.exists());
        let mut f = File::create(&valid_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        valid_f = Some(f);
      }
      let init_time = Instant::now();
      return CheckpointState{
        cfg:          cfg,
        config_file:  cfg_f,
        train_file:   trace_f.map(|f| CsvWriter::from_writer(f)),
        valid_file:   valid_f.map(|f| CsvWriter::from_writer(f)),
        start_time:   init_time,
        lap_time:     init_time,
        elapsed_s:    0.0,
      };
    }
  }

  pub fn start_timing(&mut self) {
    self.start_time = Instant::now();
  }

  pub fn stop_timing(&mut self) {
    self.lap_time = Instant::now();
    let duration = self.lap_time - self.start_time;
    self.elapsed_s = duration.as_secs() as f64 + 1.0e-9 * duration.subsec_nanos() as f64;
  }

  pub fn elapsed(&self) -> f64 {
    self.elapsed_s
  }

  pub fn append_config_info<U>(&mut self, info: &U) where U: Debug {
    if let Some(ref mut config_file) = self.config_file {
      writeln!(config_file, "{:?}", info).unwrap();
    }
  }

  pub fn append_class_stats_train(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_train_info(&stats.to_record(elapsed));
  }

  pub fn append_train_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut train_file) = self.train_file {
      train_file.encode(rec).unwrap();
      //train_file.flush().unwrap();
    }
  }

  pub fn append_class_stats_valid(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_valid_info(&stats.to_record(elapsed));
  }

  pub fn append_valid_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut valid_file) = self.valid_file {
      valid_file.encode(rec).unwrap();
      valid_file.flush().unwrap();
    }
  }
}

pub trait TraceRecord {
  fn loss(&self) -> f32;
  fn other(&self) -> f32;
}

#[derive(Clone, Debug)]
pub enum StepSize {
  Constant(f32),
  Custom{init_step: f32, steps: Vec<(usize, f32)>},
  Decay{init_step: f32, step_decay: f32, decay_iters: usize},
  Adaptive{init_step: f32, test_iters: usize, epoch_iters: usize, sched: AdaptiveStepSizeSchedule},
  BacktrackingLineSearch{decay: f32, c: f32},
  //WeakWolfeLineSearch,
}

#[derive(Clone, Copy, Debug)]
pub enum AdaptiveStepSizeSchedule {
  Pow10,
  Decimal,
}

pub fn adaptive_pow10_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 2] = [0.3,    0.1];
  const F2: [f32; 2] = [0.03,   0.01];
  const F3: [f32; 2] = [0.003,  0.001];
  const F4: [f32; 2] = [0.0003, 0.0001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 2 {
    F1[t-1]
  } else if t > 2 && t <= 4 {
    F2[t-2-1]
  } else if t > 4 && t <= 6 {
    F3[t-4-1]
  } else if t > 6 && t <= 8 {
    F4[t-6-1]
  } else {
    unimplemented!();
  }
}

pub fn adaptive_decimal_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 9] = [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1];
  const F2: [f32; 9] = [0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02, 0.01];
  const F3: [f32; 9] = [0.009, 0.008, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 9 {
    F1[t-1]
  } else if t > 9 && t <= 18 {
    F2[t-9-1]
  } else if t > 18 && t <= 27 {
    F3[t-18-1]
  } else {
    unimplemented!();
  }
}

#[derive(Clone, Copy, Debug)]
pub enum GradientMomentum {
  HeavyBall(f32),
  Nesterov(f32),
}

#[derive(Clone, Copy, Debug)]
pub enum NesterovParamState {
  Orig,
  PlusMomentum,
}

#[derive(Clone, Copy, Debug)]
pub struct StepStats {
  pub elapsed:  Option<f64>,
}

pub trait OptWorker<T, S> {
  type Rng: Rng;

  //fn init_param(&mut self, rng: &mut Xorshiftplus128Rng);
  fn init_param(&mut self, rng: &mut Self::Rng);
  /*fn load_local_param(&mut self, param_reader: &mut ReadBuffer<T>);
  fn store_local_param(&mut self, param_writer: &mut WriteBuffer<T>);
  fn store_global_param(&mut self, param_writer: &mut WriteBuffer<T>);*/

  fn step(&mut self, samples: &mut Iterator<Item=S>) /* -> StepStats*/;
  fn eval(&mut self, epoch_size: usize, samples: &mut Iterator<Item=S>);
}

pub trait OptCheckpoint<Format> where Format: CheckpointFormat {
  fn save_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
  fn restore_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
}

pub trait OptStats<Stats> {
  fn reset_opt_stats(&mut self);
  fn get_opt_stats(&self) -> &Stats;
}

pub trait OptUpdateStats<Stats> {
  fn update_stats(&mut self, stats: &mut Stats);
}

#[derive(Clone, Default, Debug)]
pub struct ClassOptStats {
  pub iter_count:       usize,
  pub sample_count:     usize,
  pub correct_count:    usize,
  pub avg_loss:         f32,
}

impl ClassOptStats {
  pub fn reset(&mut self) {
    self.iter_count = 0;
    self.sample_count = 0;
    self.correct_count = 0;
    self.avg_loss = 0.0;
  }

  pub fn accuracy(&self) -> f32 {
    self.correct_count as f32 / self.sample_count as f32
  }
}

#[derive(Clone, Default, Debug)]
pub struct RegressOptStats {
  pub avg_loss:         f32,
}
<commit_msg>Increase the random checkpoint creation delay.<commit_after>use prelude::*;
use super::{CheckpointFormat};
use rw::{ReadBuffer, WriteBuffer};

use csv::{Writer as CsvWriter};
use densearray::{Reshape, ReshapeMut};

use rand::{Rng, thread_rng};
use rustc_serialize::{Encodable};
use std::cmp::{max, min};
use std::fmt::{Debug};
use std::fs::{File, create_dir_all};
use std::io::{Write};
use std::path::{Path, PathBuf};
use std::thread::{sleep};
use std::time::{Duration, Instant};

//pub mod adagrad;
pub mod adagrad_new;
//pub mod adam;
pub mod adam_new;
//pub mod rmsprop;
//pub mod sgd;
pub mod sgd_new;
//pub mod shared_sgd;
pub mod shared_sgd_new;

#[derive(Clone, Debug)]
pub struct CheckpointConfig {
  pub prefix:   PathBuf,
  pub trace:    bool,
}

pub struct CheckpointState {
  pub cfg:          CheckpointConfig,
  pub config_file:  Option<File>,
  pub train_file:   Option<CsvWriter<File>>,
  pub valid_file:   Option<CsvWriter<File>>,
  start_time:   Instant,
  lap_time:     Instant,
  elapsed_s:    f64,
}

impl CheckpointState {
  pub fn new(cfg: CheckpointConfig) -> CheckpointState {
    Self::with_fields(cfg, "iter,loss,accuracy,elapsed")
  }

  pub fn with_fields(cfg: CheckpointConfig, fields: &str) -> CheckpointState {
    let delay_ns = thread_rng().gen_range(100_000_000, 500_000_000);
    sleep(Duration::new(0, delay_ns));
    create_dir_all(&cfg.prefix).ok();
    loop {
      let mut lo_idx = Some(0);
      let mut hi_idx = None;
      let mut idx = 0;
      while lo_idx != hi_idx {
        match (lo_idx, hi_idx) {
          (Some(lo), None) => {
            idx = lo;
          }
          (Some(lo), Some(hi)) => {
            idx = (lo + hi) / 2;
          }
          _ => unreachable!(),
        }
        let mut config_path = PathBuf::from(&cfg.prefix);
        let mut config_filename = format!("config.{}", idx);
        config_path.push(&config_filename);
        if config_path.exists() {
          match (lo_idx, hi_idx) {
            (Some(lo), None) => {
              lo_idx = Some(lo + max(1, lo));
            }
            (Some(lo), Some(hi)) => {
              lo_idx = Some(min(hi, max(lo + 1, idx)));
            }
            _ => unreachable!(),
          }
        } else {
          match (lo_idx, hi_idx) {
            (Some(_), None) => {
              lo_idx = Some(idx / 2);
              hi_idx = Some(idx);
            }
            (Some(_), Some(_)) => {
              hi_idx = Some(idx);
            }
            _ => unreachable!(),
          }
        }
      }
      idx = hi_idx.unwrap();
      let mut cfg_f = None;
      let mut trace_f = None;
      let mut valid_f = None;
      let mut config_path = PathBuf::from(&cfg.prefix);
      let mut config_filename = format!("config.{}", idx);
      config_path.push(&config_filename);
      if config_path.exists() {
        continue;
      }
      match File::create(&config_path) {
        Err(_) => {
          continue;
        }
        Ok(f) => {
          cfg_f = Some(f);
        }
      }
      if cfg.trace {
        let mut train_path = PathBuf::from(&cfg.prefix);
        let mut train_filename = format!("train.log.{}", idx);
        train_path.push(&train_filename);
        assert!(!train_path.exists());
        let mut f = File::create(&train_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        trace_f = Some(f);

        let mut valid_path = PathBuf::from(&cfg.prefix);
        let mut valid_filename = format!("valid.log.{}", idx);
        valid_path.push(&valid_filename);
        assert!(!valid_path.exists());
        let mut f = File::create(&valid_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        valid_f = Some(f);
      }
      let init_time = Instant::now();
      return CheckpointState{
        cfg:          cfg,
        config_file:  cfg_f,
        train_file:   trace_f.map(|f| CsvWriter::from_writer(f)),
        valid_file:   valid_f.map(|f| CsvWriter::from_writer(f)),
        start_time:   init_time,
        lap_time:     init_time,
        elapsed_s:    0.0,
      };
    }
  }

  pub fn start_timing(&mut self) {
    self.start_time = Instant::now();
  }

  pub fn stop_timing(&mut self) {
    self.lap_time = Instant::now();
    let duration = self.lap_time - self.start_time;
    self.elapsed_s = duration.as_secs() as f64 + 1.0e-9 * duration.subsec_nanos() as f64;
  }

  pub fn elapsed(&self) -> f64 {
    self.elapsed_s
  }

  pub fn append_config_info<U>(&mut self, info: &U) where U: Debug {
    if let Some(ref mut config_file) = self.config_file {
      writeln!(config_file, "{:?}", info).unwrap();
    }
  }

  pub fn append_class_stats_train(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_train_info(&stats.to_record(elapsed));
  }

  pub fn append_train_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut train_file) = self.train_file {
      train_file.encode(rec).unwrap();
      //train_file.flush().unwrap();
    }
  }

  pub fn append_class_stats_valid(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_valid_info(&stats.to_record(elapsed));
  }

  pub fn append_valid_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut valid_file) = self.valid_file {
      valid_file.encode(rec).unwrap();
      valid_file.flush().unwrap();
    }
  }
}

pub trait TraceRecord {
  fn loss(&self) -> f32;
  fn other(&self) -> f32;
}

#[derive(Clone, Debug)]
pub enum StepSize {
  Constant(f32),
  Custom{init_step: f32, steps: Vec<(usize, f32)>},
  Decay{init_step: f32, step_decay: f32, decay_iters: usize},
  Adaptive{init_step: f32, test_iters: usize, epoch_iters: usize, sched: AdaptiveStepSizeSchedule},
  BacktrackingLineSearch{decay: f32, c: f32},
  //WeakWolfeLineSearch,
}

#[derive(Clone, Copy, Debug)]
pub enum AdaptiveStepSizeSchedule {
  Pow10,
  Decimal,
}

pub fn adaptive_pow10_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 2] = [0.3,    0.1];
  const F2: [f32; 2] = [0.03,   0.01];
  const F3: [f32; 2] = [0.003,  0.001];
  const F4: [f32; 2] = [0.0003, 0.0001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 2 {
    F1[t-1]
  } else if t > 2 && t <= 4 {
    F2[t-2-1]
  } else if t > 4 && t <= 6 {
    F3[t-4-1]
  } else if t > 6 && t <= 8 {
    F4[t-6-1]
  } else {
    unimplemented!();
  }
}

pub fn adaptive_decimal_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 9] = [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1];
  const F2: [f32; 9] = [0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02, 0.01];
  const F3: [f32; 9] = [0.009, 0.008, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 9 {
    F1[t-1]
  } else if t > 9 && t <= 18 {
    F2[t-9-1]
  } else if t > 18 && t <= 27 {
    F3[t-18-1]
  } else {
    unimplemented!();
  }
}

#[derive(Clone, Copy, Debug)]
pub enum GradientMomentum {
  HeavyBall(f32),
  Nesterov(f32),
}

#[derive(Clone, Copy, Debug)]
pub enum NesterovParamState {
  Orig,
  PlusMomentum,
}

#[derive(Clone, Copy, Debug)]
pub struct StepStats {
  pub elapsed:  Option<f64>,
}

pub trait OptWorker<T, S> {
  type Rng: Rng;

  //fn init_param(&mut self, rng: &mut Xorshiftplus128Rng);
  fn init_param(&mut self, rng: &mut Self::Rng);
  /*fn load_local_param(&mut self, param_reader: &mut ReadBuffer<T>);
  fn store_local_param(&mut self, param_writer: &mut WriteBuffer<T>);
  fn store_global_param(&mut self, param_writer: &mut WriteBuffer<T>);*/

  fn step(&mut self, samples: &mut Iterator<Item=S>) /* -> StepStats*/;
  fn eval(&mut self, epoch_size: usize, samples: &mut Iterator<Item=S>);
}

pub trait OptCheckpoint<Format> where Format: CheckpointFormat {
  fn save_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
  fn restore_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
}

pub trait OptStats<Stats> {
  fn reset_opt_stats(&mut self);
  fn get_opt_stats(&self) -> &Stats;
}

pub trait OptUpdateStats<Stats> {
  fn update_stats(&mut self, stats: &mut Stats);
}

#[derive(Clone, Default, Debug)]
pub struct ClassOptStats {
  pub iter_count:       usize,
  pub sample_count:     usize,
  pub correct_count:    usize,
  pub avg_loss:         f32,
}

impl ClassOptStats {
  pub fn reset(&mut self) {
    self.iter_count = 0;
    self.sample_count = 0;
    self.correct_count = 0;
    self.avg_loss = 0.0;
  }

  pub fn accuracy(&self) -> f32 {
    self.correct_count as f32 / self.sample_count as f32
  }
}

#[derive(Clone, Default, Debug)]
pub struct RegressOptStats {
  pub avg_loss:         f32,
}
<|endoftext|>


<commit_before>use super::super::Error;

use std::fs::symlink_metadata;
use std::path::{Path, PathBuf};
// needed to get dev for metadata (aliased as st_dev on Linux)
use std::os::unix::fs::MetadataExt;

/// Find the mountpoint for the volume containing the (previously canonicalized) provided path.
///
/// This version relies on Unix-only extensions, but is safe.
///
/// It presumes that you will be passing in fully-qualified canonical paths.
#[cfg(unix)]
pub fn find_mountpoint_pre_canonicalized(path: &Path) -> Result<&Path, Error> {
    let mut lstats = symlink_metadata(path)?;
    let start_dev = lstats.dev();

    let mut mountpoint = path;
    loop {
        let current = match mountpoint.parent() {
            Some(p) => p,
            None => return Ok(mountpoint),
        };
        lstats = symlink_metadata(current)?;
        if lstats.dev() != start_dev {
            break;
        }
        mountpoint = current;
    }

    // I may remove these later, but for now I want to verify that these invariants hold in the
    // wild.
    assert!(path.starts_with(mountpoint));
    assert!(mountpoint.as_os_str().len() > 0);

    Ok(mountpoint)
}

/// Find the mountpoint for the volume containing the provided path.
///
/// Canonicalizes the path before calling `find_mountpoint_pre_canonicalized`. Because
/// canonicalization produces a PathBuf, lifetime management requires returning an owned path,
/// hence returns a PathBuf instead of a reference to a Path.
#[cfg(unix)]
pub fn find_mountpoint(path: &Path) -> Result<PathBuf, Error> {
    let canonicalized = path.canonicalize()?;
    let found = find_mountpoint_pre_canonicalized(canonicalized.as_path())?;
    Ok(found.to_path_buf())
}
<commit_msg>extend narrower inclusion to unix<commit_after>#[cfg(unix)]
use super::super::Error;

#[cfg(unix)]
use std::path::{Path, PathBuf};

/// Find the mountpoint for the volume containing the (previously canonicalized) provided path.
///
/// This version relies on Unix-only extensions, but is safe.
///
/// It presumes that you will be passing in fully-qualified canonical paths.
#[cfg(unix)]
pub fn find_mountpoint_pre_canonicalized(path: &Path) -> Result<&Path, Error> {
    use std::fs::symlink_metadata;
    // needed to get dev for metadata (aliased as st_dev on Linux)
    use std::os::unix::fs::MetadataExt;

    let mut lstats = symlink_metadata(path)?;
    let start_dev = lstats.dev();

    let mut mountpoint = path;
    loop {
        let current = match mountpoint.parent() {
            Some(p) => p,
            None => return Ok(mountpoint),
        };
        lstats = symlink_metadata(current)?;
        if lstats.dev() != start_dev {
            break;
        }
        mountpoint = current;
    }

    // I may remove these later, but for now I want to verify that these invariants hold in the
    // wild.
    assert!(path.starts_with(mountpoint));
    assert!(mountpoint.as_os_str().len() > 0);

    Ok(mountpoint)
}

/// Find the mountpoint for the volume containing the provided path.
///
/// Canonicalizes the path before calling `find_mountpoint_pre_canonicalized`. Because
/// canonicalization produces a PathBuf, lifetime management requires returning an owned path,
/// hence returns a PathBuf instead of a reference to a Path.
#[cfg(unix)]
pub fn find_mountpoint(path: &Path) -> Result<PathBuf, Error> {
    let canonicalized = path.canonicalize()?;
    let found = find_mountpoint_pre_canonicalized(canonicalized.as_path())?;
    Ok(found.to_path_buf())
}
<|endoftext|>


<commit_before>use luminance::{Dim2, Equation, Factor, Flat, Mode, Pipe, RenderCommand, ShadingCommand, Tess, TessRender, TessVertices, Uniform, Unit, Vertex, VertexFormat};
use luminance::shader::program::AlterUniform;
use std::cell::{Ref, RefCell, RefMut};

use compositing;
use resource::Res;
use scene::Scene;
use shader::Program;
use text::TextTexture;
use texture::{RGBA32F, Texture};

/// Vertex used in overlay’s objects. Position coordinates are in *window space*.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vert {
  /// Position.
  pub pos: [f32; 3],
  /// Color.
  pub color: [f32; 4]
}

impl Vert {
  pub fn new(pos: [f32; 3], color: [f32; 4]) -> Self {
    Vert {
      pos: pos,
      color: color
    }
  }

  /// Convert the vertex’ position to *clip space*.
  ///
  /// > Note: the depth coordinate is not affected.
  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    let converted = converter.from_win_coord(self.pos[0], self.pos[1]);
    let pos_ = [converted[0], converted[1], self.pos[2]];

    Vert {
      pos: pos_,
      color: self.color
    }
  }
}

impl Vertex for Vert {
  fn vertex_format() -> VertexFormat {
    <([f32; 3], [f32; 4]) as Vertex>::vertex_format()
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Triangle(pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Quad(pub Vert, pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Disc {
  center: Vert,
  radius: f32
}

impl Disc {
  pub fn new(center: Vert, radius: f32) -> Self {
    Disc {
      center: center,
      radius: radius
    }
  }

  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    Disc {
      center: self.center.to_clip_space(converter),
      radius: self.radius * converter.rw
    }
  }
}

impl Vertex for Disc {
  fn vertex_format() -> VertexFormat {
    <(Vert, f32) as Vertex>::vertex_format()
  }
}

pub type Texture2D = Texture<Flat, Dim2, RGBA32F>;

#[derive(Copy, Clone)]
pub struct Text<'a> {
  text_texture: &'a TextTexture,
  left_lower: Vert
}

impl<'a> Text<'a> {
  pub fn new(text_texture: &'a TextTexture, left_lower: Vert) -> Self {
    Text {
      text_texture: text_texture,
      left_lower: left_lower
    }
  }
}

const DISC_SCREEN_RATIO: &'static Uniform<f32> = &Uniform::new(0);

const TEXT_SAMPLER: &'static Uniform<Unit> = &Uniform::new(0);
const TEXT_POS: &'static Uniform<[f32; 3]> = &Uniform::new(1);
const TEXT_SIZE: &'static Uniform<[f32; 2]> = &Uniform::new(2);
const TEXT_SCALE: &'static Uniform<f32> = &Uniform::new(3);
const TEXT_COLOR: &'static Uniform<[f32; 4]> = &Uniform::new(4);

pub struct Overlay {
  ratio: f32,
  tri_program: Res<Program>,
  tris: RefCell<Tess>,
  disc_program: Res<Program>,
  discs: RefCell<Tess>,
  text_program: Res<Program>,
  text_quad: Tess,
  unit_converter: UnitConverter,
}

impl Overlay {
  pub fn new(w: u32, h: u32, max_tris: usize, max_quads: usize, max_discs: usize, scene: &mut Scene) -> Self {
    let tri_program = scene.get("spectra/overlay/triangle.glsl", vec![]).unwrap();
    let tris = Tess::new(Mode::Triangle, TessVertices::Reserve::<Vert>(max_tris * 3 + max_quads * 4), None);

    let disc_program = scene.get("spectra/overlay/disc.glsl", vec![DISC_SCREEN_RATIO.sem("ratio")]).unwrap();
    let discs = Tess::new(Mode::Point, TessVertices::Reserve::<Disc>(max_discs), None);

    let text_program = scene.get("spectra/overlay/text.glsl", vec![
      TEXT_SAMPLER.sem("text_texture"),
      TEXT_POS.sem("pos"),
      TEXT_SIZE.sem("size"),
      TEXT_SCALE.sem("scale"),
      TEXT_COLOR.sem("color")
    ]).unwrap();

    let text_quad = Tess::attributeless(Mode::TriangleStrip, 4);

    Overlay {
      ratio: w as f32 / h as f32,
      tri_program: tri_program,
      tris: RefCell::new(tris),
      disc_program: disc_program,
      discs: RefCell::new(discs),
      text_program: text_program,
      text_quad: text_quad,
      unit_converter: UnitConverter::new(w, h)
    }
  }

  /// Dispatch render input primitives into GPU buffers.
  fn dispatch(&self, input: &RenderInput) -> (usize, usize) {
    let mut tris_ref = self.tris.borrow_mut();
    let mut tris = tris_ref.as_slice_mut().unwrap();
    let mut tri_i = 0;

    let mut discs_ref = self.discs.borrow_mut();
    let mut discs = discs_ref.as_slice_mut().unwrap();
    let mut disc_i = 0;

    for &Triangle(a, b, c) in input.triangles {
      let abc = [a, b, c];

      for &v in &abc {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for &Quad(a, b, c, d) in input.quads {
      let abcd = [a, b, c, c, b, d];

      for &v in &abcd {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for disc in input.discs {
      discs[disc_i] = disc.to_clip_space(&self.unit_converter);
      disc_i += 1;
    }

    (tri_i, disc_i)
  }

  pub fn render<F, R>(&self, input: RenderInput, f: F) -> R where F: FnOnce(Render) -> R {
    let (tri_vert_nb, disc_vert_nb) = self.dispatch(&input);

    let tris_ref = self.tris.borrow();
    let tris = TessRender::one_sub(&tris_ref, tri_vert_nb);

    let discs_ref = self.discs.borrow();
    let discs = TessRender::one_sub(&discs_ref, disc_vert_nb);

    let text_quad = TessRender::one_whole(&self.text_quad);
    let text_quad_render = [Pipe::new(text_quad)];

    let tri_program = self.tri_program.borrow();
    let disc_program = self.disc_program.borrow();
    let text_program = self.text_program.borrow();

    // FIXME: no alloc?
    let text_uniforms: Vec<_> = input.texts.map(|(texts, text_scale)| texts.iter().map(|text| {
      let (tex_w, tex_h) = text.text_texture.size();

      [
        TEXT_SAMPLER.alter(Unit::new(0)),
        TEXT_POS.alter(text.left_lower.to_clip_space(&self.unit_converter).pos),
        TEXT_SIZE.alter(self.unit_converter.from_win_dim(tex_w as f32, tex_h as f32)),
        TEXT_SCALE.alter(text_scale),
        TEXT_COLOR.alter(text.left_lower.color),
      ]
    }).collect()).unwrap_or(Vec::new());

    let text_textures: Vec<_> = input.texts.map(|(texts, _)| texts.iter().map(|text| [&***text.text_texture]).collect()).unwrap_or(Vec::new());

    let text_nb = input.texts.map(|(texts, _)| texts.len()).unwrap_or(0);
    let text_render_cmds: Vec<_> = (0..text_nb).map(|i| {
        let blending = (Equation::Additive, Factor::One, Factor::SrcAlphaComplement);
        Pipe::empty()
          .uniforms(&text_uniforms[i])
          .textures(&text_textures[i])
          .unwrap(RenderCommand::new(Some(blending), true, &text_quad_render))
      }).collect();

    let disc_uniforms = [
      DISC_SCREEN_RATIO.alter(self.ratio)
    ];

    let tris = &[Pipe::new(tris)];
    let tris_render_cmds = &[Pipe::new(RenderCommand::new(None, true, tris))];
    let discs = &[Pipe::new(discs)];
    let discs_render_cmds = &[Pipe::new(RenderCommand::new(None, true, discs))];
    let shading_cmds = &[
      Pipe::new(ShadingCommand::new(&tri_program, tris_render_cmds)),
      Pipe::empty().uniforms(&disc_uniforms).unwrap(ShadingCommand::new(&disc_program, discs_render_cmds)),
      Pipe::new(ShadingCommand::new(&text_program, &text_render_cmds))
    ];

    let render = Render::new(shading_cmds);
    f(render)
  }
}

struct Render<'a, 'b> where 'b: 'a {
  shading_cmds: &'a [Pipe<'b, ShadingCommand<'b>>]
}

impl<'a, 'b> Render<'a, 'b> where 'b: 'a {
  fn new(shading_cmds: &'a [Pipe<'b, ShadingCommand<'b>>]) -> Self {
    Render {
      shading_cmds: shading_cmds
    }
  }
}

#[derive(Clone)]
pub struct RenderInput<'a, 'b> where 'b: 'a {
  triangles: &'a [Triangle],
  quads: &'a [Quad],
  discs: &'a [Disc],
  texts: Option<(&'a [Text<'b>], f32)>
}

impl<'a, 'b> RenderInput<'a, 'b> where 'b: 'a {
  pub fn new() -> Self {
    RenderInput {
      triangles: &[],
      quads: &[],
      discs: &[],
      texts: None,
    }
  }

  pub fn triangles(self, triangles: &'a [Triangle]) -> Self {
    RenderInput {
      triangles: triangles,
      ..self
    }
  }

  pub fn quads(self, quads: &'a [Quad]) -> Self {
    RenderInput {
      quads: quads,
      ..self
    }
  }

  pub fn discs(self, discs: &'a [Disc]) -> Self {
    RenderInput {
      discs: discs,
      ..self
    }
  }

  pub fn texts(self, texts: &'a [Text<'b>], scale: f32) -> Self {
    RenderInput {
      texts: Some((texts, scale.max(0.))),
      ..self
    }
  }
}

/// A *unit converter* is used to position stuff in overlay in a universal and screen independent
/// way.
///
/// The idea is that you provide should handle *window space* coordinates only. This type will then
/// help compute normalized coordinates the renderer can understand.
///
/// For the record, *window space* coordinates are defined as below – given a viewport size of
/// *w × h*:
///
/// ^ y = h
/// |
/// |
/// |    x = w
/// O------>
///
/// The formula used to convert from *window space* to what we call *clip space* is:
///
/// > x' = 2x / w - 1
/// > y' = 2y / h - 1
#[derive(Copy, Clone, Debug, PartialEq)]
struct UnitConverter {
  rw: f32,
  rh: f32,
  twice_rw: f32,
  twice_rh: f32
}

impl UnitConverter {
  /// Build a unit converter by giving it the size of the viewport.
  pub fn new(w: u32, h: u32) -> Self {
    let rw = 1. / (w as f32);
    let rh = 1. / (h as f32);

    UnitConverter {
      rw: rw,
      rh: rh,
      twice_rw: 2. * rw,
      twice_rh: 2. * rh
    }
  }

  /// Convert from *window space* coordinates to clip space* ones.
  pub fn from_win_coord(&self, x: f32, y: f32) -> [f32; 2] {
    let x_ = x * self.twice_rw - 1.;
    let y_ = y * self.twice_rh - 1.;

    [x_.min(1.).max(-1.), y_.min(1.).max(-1.)]
  }

  /// Convert from *window space* dimensions to clip space* ones.
  pub fn from_win_dim(&self, w: f32, h: f32) -> [f32; 2] {
    let w_ = w * self.rw;
    let h_ = h * self.rh;

    [w_.min(1.).max(-1.), h_.min(1.).max(-1.)]
  }
}
<commit_msg>Fixed overlay warnings.<commit_after>use luminance::{Dim2, Equation, Factor, Flat, Mode, Pipe, RenderCommand, ShadingCommand, Tess, TessRender, TessVertices, Uniform, Unit, Vertex, VertexFormat};
use std::cell::RefCell;

use compositing;
use resource::Res;
use scene::Scene;
use shader::Program;
use text::TextTexture;
use texture::{RGBA32F, Texture};

/// Vertex used in overlay’s objects. Position coordinates are in *window space*.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vert {
  /// Position.
  pub pos: [f32; 3],
  /// Color.
  pub color: [f32; 4]
}

impl Vert {
  pub fn new(pos: [f32; 3], color: [f32; 4]) -> Self {
    Vert {
      pos: pos,
      color: color
    }
  }

  /// Convert the vertex’ position to *clip space*.
  ///
  /// > Note: the depth coordinate is not affected.
  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    let converted = converter.from_win_coord(self.pos[0], self.pos[1]);
    let pos_ = [converted[0], converted[1], self.pos[2]];

    Vert {
      pos: pos_,
      color: self.color
    }
  }
}

impl Vertex for Vert {
  fn vertex_format() -> VertexFormat {
    <([f32; 3], [f32; 4]) as Vertex>::vertex_format()
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Triangle(pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Quad(pub Vert, pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Disc {
  center: Vert,
  radius: f32
}

impl Disc {
  pub fn new(center: Vert, radius: f32) -> Self {
    Disc {
      center: center,
      radius: radius
    }
  }

  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    Disc {
      center: self.center.to_clip_space(converter),
      radius: self.radius * converter.rw
    }
  }
}

impl Vertex for Disc {
  fn vertex_format() -> VertexFormat {
    <(Vert, f32) as Vertex>::vertex_format()
  }
}

pub type Texture2D = Texture<Flat, Dim2, RGBA32F>;

#[derive(Copy, Clone)]
pub struct Text<'a> {
  text_texture: &'a TextTexture,
  left_lower: Vert
}

impl<'a> Text<'a> {
  pub fn new(text_texture: &'a TextTexture, left_lower: Vert) -> Self {
    Text {
      text_texture: text_texture,
      left_lower: left_lower
    }
  }
}

const DISC_SCREEN_RATIO: &'static Uniform<f32> = &Uniform::new(0);

const TEXT_SAMPLER: &'static Uniform<Unit> = &Uniform::new(0);
const TEXT_POS: &'static Uniform<[f32; 3]> = &Uniform::new(1);
const TEXT_SIZE: &'static Uniform<[f32; 2]> = &Uniform::new(2);
const TEXT_SCALE: &'static Uniform<f32> = &Uniform::new(3);
const TEXT_COLOR: &'static Uniform<[f32; 4]> = &Uniform::new(4);

pub struct Overlay {
  ratio: f32,
  tri_program: Res<Program>,
  tris: RefCell<Tess>,
  disc_program: Res<Program>,
  discs: RefCell<Tess>,
  text_program: Res<Program>,
  text_quad: Tess,
  unit_converter: UnitConverter,
}

impl Overlay {
  pub fn new(w: u32, h: u32, max_tris: usize, max_quads: usize, max_discs: usize, scene: &mut Scene) -> Self {
    let tri_program = scene.get("spectra/overlay/triangle.glsl", vec![]).unwrap();
    let tris = Tess::new(Mode::Triangle, TessVertices::Reserve::<Vert>(max_tris * 3 + max_quads * 4), None);

    let disc_program = scene.get("spectra/overlay/disc.glsl", vec![DISC_SCREEN_RATIO.sem("ratio")]).unwrap();
    let discs = Tess::new(Mode::Point, TessVertices::Reserve::<Disc>(max_discs), None);

    let text_program = scene.get("spectra/overlay/text.glsl", vec![
      TEXT_SAMPLER.sem("text_texture"),
      TEXT_POS.sem("pos"),
      TEXT_SIZE.sem("size"),
      TEXT_SCALE.sem("scale"),
      TEXT_COLOR.sem("color")
    ]).unwrap();

    let text_quad = Tess::attributeless(Mode::TriangleStrip, 4);

    Overlay {
      ratio: w as f32 / h as f32,
      tri_program: tri_program,
      tris: RefCell::new(tris),
      disc_program: disc_program,
      discs: RefCell::new(discs),
      text_program: text_program,
      text_quad: text_quad,
      unit_converter: UnitConverter::new(w, h)
    }
  }

  /// Dispatch render input primitives into GPU buffers.
  fn dispatch(&self, input: &RenderInput) -> (usize, usize) {
    let mut tris_ref = self.tris.borrow_mut();
    let mut tris = tris_ref.as_slice_mut().unwrap();
    let mut tri_i = 0;

    let mut discs_ref = self.discs.borrow_mut();
    let mut discs = discs_ref.as_slice_mut().unwrap();
    let mut disc_i = 0;

    for &Triangle(a, b, c) in input.triangles {
      let abc = [a, b, c];

      for &v in &abc {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for &Quad(a, b, c, d) in input.quads {
      let abcd = [a, b, c, c, b, d];

      for &v in &abcd {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for disc in input.discs {
      discs[disc_i] = disc.to_clip_space(&self.unit_converter);
      disc_i += 1;
    }

    (tri_i, disc_i)
  }

  pub fn render<F, R>(&self, input: RenderInput, f: F) -> R where F: FnOnce(Render) -> R {
    let (tri_vert_nb, disc_vert_nb) = self.dispatch(&input);

    let tris_ref = self.tris.borrow();
    let tris = TessRender::one_sub(&tris_ref, tri_vert_nb);

    let discs_ref = self.discs.borrow();
    let discs = TessRender::one_sub(&discs_ref, disc_vert_nb);

    let text_quad = TessRender::one_whole(&self.text_quad);
    let text_quad_render = [Pipe::new(text_quad)];

    let tri_program = self.tri_program.borrow();
    let disc_program = self.disc_program.borrow();
    let text_program = self.text_program.borrow();

    // FIXME: no alloc?
    let text_uniforms: Vec<_> = input.texts.map(|(texts, text_scale)| texts.iter().map(|text| {
      let (tex_w, tex_h) = text.text_texture.size();

      [
        TEXT_SAMPLER.alter(Unit::new(0)),
        TEXT_POS.alter(text.left_lower.to_clip_space(&self.unit_converter).pos),
        TEXT_SIZE.alter(self.unit_converter.from_win_dim(tex_w as f32, tex_h as f32)),
        TEXT_SCALE.alter(text_scale),
        TEXT_COLOR.alter(text.left_lower.color),
      ]
    }).collect()).unwrap_or(Vec::new());

    let text_textures: Vec<_> = input.texts.map(|(texts, _)| texts.iter().map(|text| [&***text.text_texture]).collect()).unwrap_or(Vec::new());

    let text_nb = input.texts.map(|(texts, _)| texts.len()).unwrap_or(0);
    let text_render_cmds: Vec<_> = (0..text_nb).map(|i| {
        let blending = (Equation::Additive, Factor::One, Factor::SrcAlphaComplement);
        Pipe::empty()
          .uniforms(&text_uniforms[i])
          .textures(&text_textures[i])
          .unwrap(RenderCommand::new(Some(blending), true, &text_quad_render))
      }).collect();

    let disc_uniforms = [
      DISC_SCREEN_RATIO.alter(self.ratio)
    ];

    let tris = &[Pipe::new(tris)];
    let tris_render_cmds = &[Pipe::new(RenderCommand::new(None, true, tris))];
    let discs = &[Pipe::new(discs)];
    let discs_render_cmds = &[Pipe::new(RenderCommand::new(None, true, discs))];
    let shading_cmds = &[
      Pipe::new(ShadingCommand::new(&tri_program, tris_render_cmds)),
      Pipe::empty().uniforms(&disc_uniforms).unwrap(ShadingCommand::new(&disc_program, discs_render_cmds)),
      Pipe::new(ShadingCommand::new(&text_program, &text_render_cmds))
    ];

    let render = Render::new(shading_cmds);
    f(render)
  }
}

pub struct Render<'a, 'b> where 'b: 'a {
  shading_cmds: &'a [Pipe<'b, ShadingCommand<'b>>]
}

impl<'a, 'b> Render<'a, 'b> where 'b: 'a {
  fn new(shading_cmds: &'a [Pipe<'b, ShadingCommand<'b>>]) -> Self {
    Render {
      shading_cmds: shading_cmds
    }
  }
}

impl<'a, 'b> compositing::Render<'b> for Render<'a, 'b> where 'b: 'a {
  fn push_shading_commands(&self, shading_commands: &mut Vec<Pipe<'b, ShadingCommand<'b>>>) {
    shading_commands.extend_from_slice(&self.shading_cmds);
  }
}

#[derive(Clone)]
pub struct RenderInput<'a, 'b> where 'b: 'a {
  triangles: &'a [Triangle],
  quads: &'a [Quad],
  discs: &'a [Disc],
  texts: Option<(&'a [Text<'b>], f32)>
}

impl<'a, 'b> RenderInput<'a, 'b> where 'b: 'a {
  pub fn new() -> Self {
    RenderInput {
      triangles: &[],
      quads: &[],
      discs: &[],
      texts: None,
    }
  }

  pub fn triangles(self, triangles: &'a [Triangle]) -> Self {
    RenderInput {
      triangles: triangles,
      ..self
    }
  }

  pub fn quads(self, quads: &'a [Quad]) -> Self {
    RenderInput {
      quads: quads,
      ..self
    }
  }

  pub fn discs(self, discs: &'a [Disc]) -> Self {
    RenderInput {
      discs: discs,
      ..self
    }
  }

  pub fn texts(self, texts: &'a [Text<'b>], scale: f32) -> Self {
    RenderInput {
      texts: Some((texts, scale.max(0.))),
      ..self
    }
  }
}

/// A *unit converter* is used to position stuff in overlay in a universal and screen independent
/// way.
///
/// The idea is that you provide should handle *window space* coordinates only. This type will then
/// help compute normalized coordinates the renderer can understand.
///
/// For the record, *window space* coordinates are defined as below – given a viewport size of
/// *w × h*:
///
/// ^ y = h
/// |
/// |
/// |    x = w
/// O------>
///
/// The formula used to convert from *window space* to what we call *clip space* is:
///
/// > x' = 2x / w - 1
/// > y' = 2y / h - 1
#[derive(Copy, Clone, Debug, PartialEq)]
struct UnitConverter {
  rw: f32,
  rh: f32,
  twice_rw: f32,
  twice_rh: f32
}

impl UnitConverter {
  /// Build a unit converter by giving it the size of the viewport.
  pub fn new(w: u32, h: u32) -> Self {
    let rw = 1. / (w as f32);
    let rh = 1. / (h as f32);

    UnitConverter {
      rw: rw,
      rh: rh,
      twice_rw: 2. * rw,
      twice_rh: 2. * rh
    }
  }

  /// Convert from *window space* coordinates to clip space* ones.
  pub fn from_win_coord(&self, x: f32, y: f32) -> [f32; 2] {
    let x_ = x * self.twice_rw - 1.;
    let y_ = y * self.twice_rh - 1.;

    [x_.min(1.).max(-1.), y_.min(1.).max(-1.)]
  }

  /// Convert from *window space* dimensions to clip space* ones.
  pub fn from_win_dim(&self, w: f32, h: f32) -> [f32; 2] {
    let w_ = w * self.rw;
    let h_ = h * self.rh;

    [w_.min(1.).max(-1.), h_.min(1.).max(-1.)]
  }
}
<|endoftext|>


<commit_before>
use node::{Expression, Grammar, Production, Term};

named!(pub terminal< &[u8], Term >,
    do_parse!(
        t: delimited!(tag!("\""), take_until!("\""), ws!(tag!("\""))) >>
        (Term::Terminal(String::from_utf8_lossy(t).into_owned()))
    )
);

named!(pub nonterminal< &[u8], Term >,
    do_parse!(
        nt: ws!(delimited!(tag!("<"), take_until_either!(" >"), tag!(">"))) >>
        (Term::Nonterminal(String::from_utf8_lossy(nt).into_owned()))
    )
);

named!(pub expression< &[u8], Expression >,
    do_parse!(
        terms: many1!(alt!(terminal | nonterminal)) >>
        ws!(alt!(tag!(";") | tag!("|"))) >>
        (Expression::from_parts(terms))
    )
);

named!(pub production< &[u8], Production >,
    do_parse!(
        lhs: nonterminal >>
        ws!(tag!("::=")) >>
        rhs: many1!(expression) >>
        (Production::from_parts(lhs, rhs))
    )
);

named!(pub grammar< &[u8], Grammar >,
    do_parse!(
        prods: many1!(production) >>
        eof!() >>
        (Grammar::from_parts(prods))
    )
);

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

    fn construct_terminal_tuple() -> (Term, String) {
        let terminal_pattern = "\"terminal pattern\"";
        let terminal_value = "terminal pattern";
        let terminal_object = Term::Terminal(String::from(terminal_value));

        (terminal_object, String::from(terminal_pattern))
    }

    #[test]
    fn terminal_match() {
        let terminal_tuple = construct_terminal_tuple();
        assert_eq!(
            terminal_tuple.0,
            terminal(terminal_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_nonterminal_tuple() -> (Term, String) {
        let nonterminal_pattern = "<nonterminal-pattern>";
        let nonterminal_value = "nonterminal-pattern";
        let nonterminal_object = Term::Nonterminal(String::from(nonterminal_value));

        (nonterminal_object, String::from(nonterminal_pattern))
    }

    #[test]
    fn nonterminal_match() {
        let nonterminal_tuple = construct_nonterminal_tuple();
        assert_eq!(
            nonterminal_tuple.0,
            nonterminal(nonterminal_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_expression_tuple() -> (Expression, String) {
        let nonterminal_tuple = construct_nonterminal_tuple();
        let terminal_tuple = construct_terminal_tuple();
        let expression_pattern = nonterminal_tuple.1 + &terminal_tuple.1 + "|";
        let expression_object = Expression::from_parts(vec![nonterminal_tuple.0, terminal_tuple.0]);

        (expression_object, String::from(expression_pattern))
    }

    #[test]
    fn expression_match() {
        let expression_tuple = construct_expression_tuple();
        assert_eq!(
            expression_tuple.0,
            expression(expression_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_production_tuple() -> (Production, String) {
        let expression_tuple = construct_expression_tuple();
        let nonterminal_tuple = construct_nonterminal_tuple();
        let terminal_tuple = construct_nonterminal_tuple();
        let production_pattern =
            nonterminal_tuple.1 + "::=" + &expression_tuple.1 + &terminal_tuple.1 + ";";
        let production_object = Production::from_parts(
            nonterminal_tuple.0,
            vec![
                expression_tuple.0.clone(),
                Expression::from_parts(vec![terminal_tuple.0]),
            ],
        );

        (production_object, String::from(production_pattern))
    }

    #[test]
    fn production_match() {
        let production_tuple = construct_production_tuple();
        assert_eq!(
            production_tuple.0,
            production(production_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_grammar_tuple() -> (Grammar, String) {
        let production_tuple = construct_production_tuple();
        let grammar_pattern = production_tuple.1.clone() + &production_tuple.1;
        let grammar_object = Grammar::from_parts(vec![
            construct_production_tuple().0.clone(),
            construct_production_tuple().0,
        ]);

        (grammar_object, String::from(grammar_pattern))
    }

    #[test]
    fn grammar_match() {
        let grammar_tuple = construct_grammar_tuple();
        println!("{:#?}", grammar_tuple.1);
        assert_eq!(
            grammar_tuple.0,
            grammar(grammar_tuple.1.as_bytes()).unwrap().1
        );
    }
}
<commit_msg>Remove print in grammar test<commit_after>
use node::{Expression, Grammar, Production, Term};

named!(pub terminal< &[u8], Term >,
    do_parse!(
        t: delimited!(tag!("\""), take_until!("\""), ws!(tag!("\""))) >>
        (Term::Terminal(String::from_utf8_lossy(t).into_owned()))
    )
);

named!(pub nonterminal< &[u8], Term >,
    do_parse!(
        nt: ws!(delimited!(tag!("<"), take_until_either!(" >"), tag!(">"))) >>
        (Term::Nonterminal(String::from_utf8_lossy(nt).into_owned()))
    )
);

named!(pub expression< &[u8], Expression >,
    do_parse!(
        terms: many1!(alt!(terminal | nonterminal)) >>
        ws!(alt!(tag!(";") | tag!("|"))) >>
        (Expression::from_parts(terms))
    )
);

named!(pub production< &[u8], Production >,
    do_parse!(
        lhs: nonterminal >>
        ws!(tag!("::=")) >>
        rhs: many1!(expression) >>
        (Production::from_parts(lhs, rhs))
    )
);

named!(pub grammar< &[u8], Grammar >,
    do_parse!(
        prods: many1!(production) >>
        eof!() >>
        (Grammar::from_parts(prods))
    )
);

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

    fn construct_terminal_tuple() -> (Term, String) {
        let terminal_pattern = "\"terminal pattern\"";
        let terminal_value = "terminal pattern";
        let terminal_object = Term::Terminal(String::from(terminal_value));

        (terminal_object, String::from(terminal_pattern))
    }

    #[test]
    fn terminal_match() {
        let terminal_tuple = construct_terminal_tuple();
        assert_eq!(
            terminal_tuple.0,
            terminal(terminal_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_nonterminal_tuple() -> (Term, String) {
        let nonterminal_pattern = "<nonterminal-pattern>";
        let nonterminal_value = "nonterminal-pattern";
        let nonterminal_object = Term::Nonterminal(String::from(nonterminal_value));

        (nonterminal_object, String::from(nonterminal_pattern))
    }

    #[test]
    fn nonterminal_match() {
        let nonterminal_tuple = construct_nonterminal_tuple();
        assert_eq!(
            nonterminal_tuple.0,
            nonterminal(nonterminal_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_expression_tuple() -> (Expression, String) {
        let nonterminal_tuple = construct_nonterminal_tuple();
        let terminal_tuple = construct_terminal_tuple();
        let expression_pattern = nonterminal_tuple.1 + &terminal_tuple.1 + "|";
        let expression_object = Expression::from_parts(vec![nonterminal_tuple.0, terminal_tuple.0]);

        (expression_object, String::from(expression_pattern))
    }

    #[test]
    fn expression_match() {
        let expression_tuple = construct_expression_tuple();
        assert_eq!(
            expression_tuple.0,
            expression(expression_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_production_tuple() -> (Production, String) {
        let expression_tuple = construct_expression_tuple();
        let nonterminal_tuple = construct_nonterminal_tuple();
        let terminal_tuple = construct_nonterminal_tuple();
        let production_pattern =
            nonterminal_tuple.1 + "::=" + &expression_tuple.1 + &terminal_tuple.1 + ";";
        let production_object = Production::from_parts(
            nonterminal_tuple.0,
            vec![
                expression_tuple.0.clone(),
                Expression::from_parts(vec![terminal_tuple.0]),
            ],
        );

        (production_object, String::from(production_pattern))
    }

    #[test]
    fn production_match() {
        let production_tuple = construct_production_tuple();
        assert_eq!(
            production_tuple.0,
            production(production_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_grammar_tuple() -> (Grammar, String) {
        let production_tuple = construct_production_tuple();
        let grammar_pattern = production_tuple.1.clone() + &production_tuple.1;
        let grammar_object = Grammar::from_parts(vec![
            construct_production_tuple().0.clone(),
            construct_production_tuple().0,
        ]);

        (grammar_object, String::from(grammar_pattern))
    }

    #[test]
    fn grammar_match() {
        let grammar_tuple = construct_grammar_tuple();
        assert_eq!(
            grammar_tuple.0,
            grammar(grammar_tuple.1.as_bytes()).unwrap().1
        );
    }
}
<|endoftext|>


<commit_before>use color::Color;

pub struct Program {
    image: Vec<Vec<Color>>,
}

impl Program {
    pub fn get(coords: (usize, usize)) -> Option<Color> {
        unimplemented!();
    }

    pub fn neighbors(coords: (usize, usize)) -> &[Color] {
        unimplemented!();
    }

    pub fn neighbors_with_coords(coords: (usize, usize)) -> &[(usize, usize, Color)] {
        unimplemented!();
    }
}
<commit_msg>Add missing `&self` parameters to `Program` methods<commit_after>use color::Color;

pub struct Program {
    image: Vec<Vec<Color>>,
}

impl Program {
    pub fn get(&self, coords: (usize, usize)) -> Option<Color> {
        unimplemented!();
    }

    pub fn neighbors(&self, coords: (usize, usize)) -> &[Color] {
        unimplemented!();
    }

    pub fn neighbors_with_coords(&self, coords: (usize, usize)) -> &[(usize, usize, Color)] {
        unimplemented!();
    }
}
<|endoftext|>