<commit_before>#[macro_use]
extern crate string_cache;
extern crate html5ever;
extern crate unicode_width;

use std::io;
use std::io::Write;
use std::cmp::max;
use html5ever::{parse_document};
use html5ever::driver::ParseOpts;
use html5ever::tree_builder::TreeBuilderOpts;
use html5ever::rcdom::{RcDom,Handle,Text,Element,Document,Comment};
use html5ever::tendril::TendrilSink;
use unicode_width::{UnicodeWidthStr,UnicodeWidthChar};

/// A dummy writer which does nothing
struct Discard {}
impl Write for Discard {
    fn write(&mut self, bytes: &[u8]) -> std::result::Result<usize, io::Error> { Ok(bytes.len()) }
    fn flush(&mut self) -> std::result::Result<(), io::Error> { Ok(()) }
}

fn wrap_text(text: &str, width: usize) -> String {
    let mut result = String::new();
    let mut xpos = 0usize;
    for word in text.split_whitespace() {
        if width <= (xpos + 1) {
            result.push('\n');
            xpos = 0;
        }
        let space_left = width - xpos - 1;
        let word_width = UnicodeWidthStr::width(word);
        if word_width <= space_left {
            /* It fits; no problem.  Add a space if not at the
             * start of line.*/
            if xpos > 0 {
                result.push(' ');
                xpos += 1;
            }
            result.push_str(word);
            xpos += word_width;
            continue;
        }

        /* It doesn't fit.  If we're not at the start of the line,
         * then go to a new line. */
        if xpos > 0 {
            result.push('\n');
            xpos = 0;
        }

        /* We're now at the start of a line. */
        if word_width > width {
            /* It doesn't fit at all on the line, so break it. */
            for c in word.chars() {
                let c_width = UnicodeWidthChar::width(c).unwrap();
                if c_width + xpos > width {
                    /* Break here */
                    result.push('\n');
                    xpos = 0;
                }
                /* This might happen with really narrow spaces... */
                assert!(c_width <= width);

                result.push(c);
                xpos += c_width;
            }
        } else {
            result.push_str(word);
            xpos += word_width;
        }
    }
    /* Terminate with a newline if needed. */
    if xpos > 0 {
        result.push('\n');
    }
    result
}

fn get_text(handle: Handle) -> String {
    let node = handle.borrow();
    let mut result = String::new();
    if let Text(ref tstr) = node.node {
        result.push_str(&tstr);
    } else {
        for child in node.children.iter() {
            result.push_str(&get_text(child.clone()));
        }
    }
    result
}

fn get_wrapped_text(handle: Handle, width: usize) -> String {
    let text = get_text(handle);
    wrap_text(&text, width)
}

fn dom_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();
    let mut result = String::new();
    match node.node {
        Document => {},
        Element(ref name, _, _) => {
            match *name {
                qualname!(html, "html") |
                qualname!(html, "div") |
                qualname!(html, "span") |
                qualname!(html, "body") => {
                    /* process children, but don't add anything */
                },
                qualname!(html, "link") |
                qualname!(html, "meta") |
                qualname!(html, "hr") |
                qualname!(html, "head") => {
                    /* Ignore the head and its children */
                    return result;
                },
                qualname!(html, "h1") |
                qualname!(html, "h2") |
                qualname!(html, "h3") |
                qualname!(html, "h4") |
                qualname!(html, "p") => {
                    return get_wrapped_text(handle.clone(), width) + "\n";
                },
                qualname!(html, "br") => {
                    result.push('\n');
                }
                qualname!(html, "table") => return table_to_string(handle.clone(), err_out, width),
                _ => {
                    write!(err_out, "Unhandled element: {:?}\n", name.local).unwrap();
                },
            }
          },
        Text(ref tstr) => {
            return wrap_text(tstr, width);
        }
        Comment(_) => {},
        _ => { write!(err_out, "Unhandled: {:?}\n", node).unwrap(); },
    }
    for child in node.children.iter() {
        result.push_str(&dom_to_string(child.clone(), err_out, width));
    }
    result
}

#[derive(Debug)]
struct TableCell {
    colspan: usize,
    content: Handle,
}

#[derive(Debug)]
struct TableRow {
    cells: Vec<TableCell>,
}

#[derive(Debug)]
struct Table {
    rows: Vec<TableRow>,
}

impl Table {
    pub fn new() -> Table {
        Table{ rows: Vec::new() }
    }
    pub fn push(&mut self, row: TableRow) {
        self.rows.push(row);
    }
    pub fn rows(&self) -> std::slice::Iter<TableRow> {
        self.rows.iter()
    }
}

impl TableRow {
    pub fn new() -> TableRow {
        TableRow{ cells: Vec::new() }
    }
    pub fn push(&mut self, cell: TableCell) {
        self.cells.push(cell);
    }
    pub fn cells(&self) -> std::slice::Iter<TableCell> {
        self.cells.iter()
    }
    /// Return an iterator over (column, &cell)s, which
    /// takes into account colspan.
    pub fn cell_columns(&self) -> Vec<(usize, &TableCell)> {
        let mut result = Vec::new();
        let mut colno = 0;
        for cell in &self.cells {
            result.push((colno, cell));
            colno += cell.colspan;
        }
        result
    }
    /// Count the number of cells in the row.
    /// Takes into account colspan.
    pub fn num_cells(&self) -> usize {
        self.cells.iter().map(|cell| cell.colspan).sum()
    }
}

impl TableCell {
    pub fn new(s: Handle) -> TableCell {
        if let Element(_, _, ref attrs) = s.borrow().node {
            let mut colspan = 1;
            for attr in attrs {
                if &attr.name.local == "colspan" {
                    let v:&str = &*attr.value;
                    colspan = v.parse().unwrap_or(1);
                } else {
                    //println!("Attr: {:?}", attr);
                }
            }
            TableCell{ content: s.clone(), colspan: colspan }
        } else {
            panic!("TableCell::new received a non-Element");
        }
    }
    pub fn render<T:Write>(&self, width: usize, err_out: &mut T) -> String
    {
        dom_to_string(self.content.clone(), err_out, width)
    }
}

fn handle_td(handle: Handle) -> TableCell {
    TableCell::new(handle)
}

fn handle_tr<T:Write>(handle: Handle, _: &mut T) -> TableRow {
    let node = handle.borrow();

    let mut row = TableRow::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "td") => {
                        row.push(handle_td(child.clone()));
                    },
                    _ => println!("  [[tr child: {:?}]]", name),
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    row
}

fn handle_tbody<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();

    let mut table = Table::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "tr") => {
                        table.push(handle_tr(child.clone(), err_out));
                    },
                    _ => println!("  [[tbody child: {:?}]]", name),
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    /* Now lay out the table.  Use the simple option of giving each column
     * same width.  TODO: be cleverer, and handle multi-width cells, etc. */
    let num_columns = table.rows().map(|r| r.num_cells()).max().unwrap();

    let mut result = String::new();

    /* Heuristic: scale the column widths according to how much content there is. */
    let test_col_width = 1000;  // Render width for measurement; shouldn't make much difference.
    let min_width = 5;
    let mut col_sizes = vec![0usize; num_columns];

    for row in table.rows() {
        let mut colno = 0;
        for cell in row.cells() {
            let celldata = cell.render(test_col_width, &mut Discard{});
            // If the cell has a colspan>1, then spread its size between the
            // columns.
            let col_size = celldata.len() / cell.colspan;
            for i in 0..cell.colspan {
                col_sizes[colno + i] += col_size;
            }
            colno += cell.colspan;
        }
    }
    let tot_size: usize = col_sizes.iter().sum();
    let mut col_widths:Vec<usize> = col_sizes.iter()
                                         .map(|sz| {
                                             if *sz == 0 {
                                                 0
                                             } else {
                                                 max(sz * width / tot_size, min_width)
                                             }
                                          }).collect();
    /* The minimums may have put the total width too high */
    while col_widths.iter().cloned().sum::<usize>() > width {
        let (i, _) = col_widths.iter().cloned().enumerate().max_by_key(|k| k.1).unwrap();
        col_widths[i] -= 1;
    }
    if col_widths.len() > 0 {
        // Slight fudge; we're not drawing extreme edges, so one of the columns
        // can gets a free character cell from not having a border.
        // make it the last.
        let last = col_widths.len() - 1;
        col_widths[last] += 1;
    }

    let mut rowline = String::new();
    for width in col_widths.iter().cloned().filter(|w:&usize| *w > 0) {
        rowline.push_str(&(0..(width-1)).map(|_| '-').collect::<String>());
        rowline.push('+');
    }
    if rowline.len() > 0 {
        rowline.pop().unwrap();  // Remove the last '+'.
    }
    result.push_str(&rowline);
    result.push('\n');

    for row in table.rows() {
        let (used_widths, formatted_cells): (Vec<usize>, Vec<String>) = row.cell_columns()
                                              .into_iter()
                                              .flat_map(|(colno, cell)| {
                                                   let col_width:usize = col_widths[colno..colno+cell.colspan]
                                                                      .iter().sum();
                                                   if col_width > 0 {
                                                       Some((col_width, cell.render(col_width-1, err_out)))
                                                   } else {
                                                       None
                                                   }
                                               })
                                              .unzip();
        let line_sets: Vec<Vec<&str>> = formatted_cells.iter()
                                                       .map(|s| s.lines()
                                                                 .map(|line| line.trim_right())
                                                                 .collect())
                                                       .collect();
        let cell_height = line_sets.iter()
                                   .map(|v| v.len())
                                   .max().unwrap_or(0);
        for i in 0..cell_height {
            for (cellno, ls) in line_sets.iter().enumerate() {
                result.push_str(&format!("{: <width$}", ls.get(i).cloned().unwrap_or(""), width = used_widths[cellno]-1));
                if cellno == line_sets.len()-1 {
                    result.push('\n')
                } else {
                    result.push('|')
                }
            }
        }
        if cell_height > 0 {
            result.push_str(&rowline);
            result.push('\n');
        }
    }

    result
}

fn table_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();
    let result = String::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "tbody") => return handle_tbody(child.clone(), err_out, width),
                    _ => { writeln!(err_out, "  [[table child: {:?}]]", name).unwrap();},
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    result
}

pub fn from_read<R>(mut input: R, width: usize) -> String where R: io::Read {
    let opts = ParseOpts {
        tree_builder: TreeBuilderOpts {
            drop_doctype: true,
            ..Default::default()
        },
        ..Default::default()
    };
    let dom = parse_document(RcDom::default(), opts)
                   .from_utf8()
                   .read_from(&mut input)
                   .unwrap();

    dom_to_string(dom.document, &mut Discard{} /* &mut io::stderr()*/, width)
}

#[cfg(test)]
mod tests {
    use super::{from_read,wrap_text};
    #[test]
    fn test_table() {
        assert_eq!(from_read(&br##"

           1
           2
           3

"##[..], 12), r#"---+---+----
1  |2  |3
---+---+----
"#);
     }

     #[test]
     fn test_colspan() {
        assert_eq!(from_read(&br##"

           1
           2
           3

           12
           3

           1
           23

"##[..], 12), r#"---+---+----
1  |2  |3
---+---+----
12     |3
---+---+----
1  |23
---+---+----
"#);
     }

     #[test]
     fn test_para() {
        assert_eq!(from_read(&b"
Hello
"[..], 10),
                   "Hello\n\n");
     }

     #[test]
     fn test_wrap() {
        assert_eq!(wrap_text("Hello", 10), "Hello\n");
     }
}
<commit_msg>Strip


<commit_before>#[crate_id = "fragments#0.1-pre"];

#[comment = "A simple template library for Rust"];
#[license = "MIT"];
#[crate_type = "lib"];
#[crate_type = "rlib"];

#[doc(html_root_url = "http://www.rust-ci.org/Ogeon/fragments/doc/")];

extern crate collections;

use std::fmt;
use std::from_str::FromStr;
use std::io::{BufReader, IoError, EndOfFile};
use std::vec_ng::Vec;
use collections::hashmap::{HashMap, HashSet};

type ParserState = Option<fn(&mut Buffer) -> ParserResult>;

struct ParserResult {
	token: Token,
	next_parser: ParserState
}

#[deriving(Eq, TotalEq, Show)]
enum Token {
	String(~str),
	Placeholder(~str),
	Conditional(~str, bool, Vec<Token>)
}

///A string template with placeholders and conditional content.
///
///Placeholders are written as `[[:label]]`, where `label` becomes the name of the placeholder.
///The label is then used to insert content: `my_template.insert(~"label", my_content);`.
///The assigned content for a placeholder can be anything that implements `Show`.
///Even other templates may be inserted, which allows a more atomic structure.
///
///Conditional segments are surrounded by `[[?label]]...[[/]]`, where `label` becomes the name of the condition,
///and they are used to display content depending on whether its label exists in the `conditions` set.
///`[[/]]` marks the end of a block and may contain other characters after the `/`, which may be useful for labeling the end mark.
///Conditions can be made negative by writing `[[?!label]]...[[/]]`, which makes the content visible if the label
///is missing from the `conditions` set.
///
///Any character can be escaped by writing `\` before it. It can be used like this: `\[[[:label1]], [[:label2]]]`
///which will result in `[content1, content2]`, since the first `[` will be ignored by the parser and just added to the
///rest of the content.
pub struct Template {
	///Content for the placeholders
	content: HashMap<~str, ~fmt::Show>,
	///Conditional switches
	conditions: HashSet<~str>,
	priv tokens: Vec<Token>
}

impl Template {
	#[inline]
	pub fn from_buffer(b: &mut Buffer) -> Template {
		Template {
			content: HashMap::new(),
			conditions: HashSet::new(),
			tokens: parse_block(b)
		}
	}

	///Convenience method for inserting content.
	#[inline]
	pub fn insert<T: fmt::Show + Send>(&mut self, placeholder: ~str, item: ~T) {
		self.content.insert(placeholder, item as ~fmt::Show);
	}

	///Convenience method for setting a condition.
	#[inline]
	pub fn set(&mut self, condition: ~str, value: bool) {
		if value {
			self.conditions.insert(condition);
		} else {
			self.conditions.remove(&condition);
		}
	}

	fn format_tokens(&self, tokens: &Vec<Token>, f: &mut fmt::Formatter) -> fmt::Result {
		for token in tokens.iter() {
			let res = match token {
				&String(ref s) => f.buf.write_str(*s),

				&Placeholder(ref k) => {
					match self.content.find(k) {
						Some(value) => value.fmt(f),
						None => Ok(())
					}
				},

				&Conditional(ref k, expected, ref tokens) => {
					if self.conditions.contains(k) == expected {
						self.format_tokens(tokens, f)
					} else {
						Ok(())
					}
				}
			};

			match res {
				Err(e) => return Err(e),
				_ => {}
			}
		}

		Ok(())
	}
}

impl FromStr for Template {
	///Creates a new `Template` from a string.
	fn from_str(s: &str) -> Option<Template> {
		Some(Template::from_buffer(&mut BufReader::new(s.as_bytes())))
	}
}

impl fmt::Show for Template {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.format_tokens(&self.tokens, f)
	}
}

fn parse_block(b: &mut Buffer) -> Vec<Token> {
	let mut tokens = vec!();
	let mut parser = parse_string;

	loop {
		let ParserResult{token: token, next_parser: next} = parser(b);

		tokens.push(token);

		match next {
			Some(p) => parser = p,
			None => break
		}
	}

	tokens
}

fn parse_string(b: &mut Buffer) -> ParserResult {
	let mut content = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						content.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok('[') => {
				match b.read_char() {
					Ok('[') => {
						match b.read_char() {
							Ok(':') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_placeholder)
							},
							Ok('?') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_conditional)
							},
							Ok('/') => {
								skip_to_token_end(b);

								return ParserResult{
									token: String(content),
									next_parser: None
								}
							},
							Ok(c) => fail!("Unknown token type: '{}'", c),
							Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
							Err(e) => fail!("{}", e)
						}
					},
					Ok(c) => {
						content.push_char('[');
						content.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => content.push_char('['),
					Err(e) => fail!("{}", e)
				}
			},
			Ok(c) => content.push_char(c),
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: String(content),
		next_parser: None
	}
}

fn skip_to_token_end(b: &mut Buffer) {
	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(_) => {},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => break,
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e),
					_ => {}
				}
			},
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e),
			_ => {}
		}
	}
}

fn parse_placeholder(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Placeholder(label),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => label.push_char(']'),
					Err(e) => fail!("{}", e)
				}
			},
			Ok(c) => label.push_char(c),
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: Placeholder(label),
		next_parser: None
	}
}

fn parse_conditional(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";
	let mut expected = true;
	let mut expected_set = false;

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Conditional(label, expected, parse_block(b)),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => label.push_char(']'),
					Err(e) => fail!("{}", e)
				}
			},
			Ok('!') => {
				if label.len() == 0 && !expected_set {
					expected = false;
					expected_set = true;
				} else {
					label.push_char('!');
				}
			},
			Ok(c) => {
				label.push_char(c)
			},
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: Conditional(label, expected, vec!()),
		next_parser: None
	}
}

#[cfg(test)]
mod test {
	use super::{Template, Placeholder, String};

	#[test]
	fn basic_tokens() {
		let template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! This is a "));
		assert_eq!(template.tokens.get(3), &Placeholder(~"something"));
		assert_eq!(template.tokens.get(4), &String(~" template."));
	}

	#[test]
	#[should_fail]
	fn strange_tokens() {
		let _: Template = from_str("Hello, [[[:name]]]! This is a [[[[:something]] template.").unwrap();
	}

	#[test]
	fn escaped_tokens() {
		let template: Template = from_str("Hello, [[:name]]! Write placeholders like \\[[:this]] and escape them like \\\\\\[[:this]]").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! Write placeholders like [[:this]] and escape them like \\[[:this]]"));
	}

	#[test]
	fn replacement() {
		let mut template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		template.insert(~"name", ~("Peter"));
		template.insert(~"something", ~("nice"));
		assert_eq!(template.to_str(), ~"Hello, Peter! This is a nice template.");
	}

	#[test]
	fn templates_in_templates() {
		let mut template1: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		let mut template2: ~Template = ~from_str("really [[:something]]").unwrap();
		template1.insert(~"name", ~("Peter"));
		template2.insert(~"something", ~("nice"));

		template1.insert(~"something", template2);

		assert_eq!(template1.to_str(), ~"Hello, Peter! This is a really nice template.");
	}

	#[test]
	fn conditional() {
		let mut template: Template = from_str("Hello, [[:name]]![[?condition]] The condition is true.[[/condition]]").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter!");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}

	#[test]
	fn conditional_switch() {
		let mut template: Template = from_str("Hello, [[:name]]! The condition is [[?condition]]true[[/condition]][[?!condition]]false[[/condition]].").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is false.");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}
}<commit_msg>`std::vec_ng` was renamed to `std::vec`<commit_after>#[crate_id = "fragments#0.1-pre"];

#[comment = "A simple template library for Rust"];
#[license = "MIT"];
#[crate_type = "lib"];
#[crate_type = "rlib"];

#[doc(html_root_url = "http://www.rust-ci.org/Ogeon/fragments/doc/")];

extern crate collections;

use std::fmt;
use std::from_str::FromStr;
use std::io::{BufReader, IoError, EndOfFile};
use std::vec::Vec;
use collections::hashmap::{HashMap, HashSet};

type ParserState = Option<fn(&mut Buffer) -> ParserResult>;

struct ParserResult {
	token: Token,
	next_parser: ParserState
}

#[deriving(Eq, TotalEq, Show)]
enum Token {
	String(~str),
	Placeholder(~str),
	Conditional(~str, bool, Vec<Token>)
}

///A string template with placeholders and conditional content.
///
///Placeholders are written as `[[:label]]`, where `label` becomes the name of the placeholder.
///The label is then used to insert content: `my_template.insert(~"label", my_content);`.
///The assigned content for a placeholder can be anything that implements `Show`.
///Even other templates may be inserted, which allows a more atomic structure.
///
///Conditional segments are surrounded by `[[?label]]...[[/]]`, where `label` becomes the name of the condition,
///and they are used to display content depending on whether its label exists in the `conditions` set.
///`[[/]]` marks the end of a block and may contain other characters after the `/`, which may be useful for labeling the end mark.
///Conditions can be made negative by writing `[[?!label]]...[[/]]`, which makes the content visible if the label
///is missing from the `conditions` set.
///
///Any character can be escaped by writing `\` before it. It can be used like this: `\[[[:label1]], [[:label2]]]`
///which will result in `[content1, content2]`, since the first `[` will be ignored by the parser and just added to the
///rest of the content.
pub struct Template {
	///Content for the placeholders
	content: HashMap<~str, ~fmt::Show>,
	///Conditional switches
	conditions: HashSet<~str>,
	priv tokens: Vec<Token>
}

impl Template {
	#[inline]
	pub fn from_buffer(b: &mut Buffer) -> Template {
		Template {
			content: HashMap::new(),
			conditions: HashSet::new(),
			tokens: parse_block(b)
		}
	}

	///Convenience method for inserting content.
	#[inline]
	pub fn insert<T: fmt::Show + Send>(&mut self, placeholder: ~str, item: ~T) {
		self.content.insert(placeholder, item as ~fmt::Show);
	}

	///Convenience method for setting a condition.
	#[inline]
	pub fn set(&mut self, condition: ~str, value: bool) {
		if value {
			self.conditions.insert(condition);
		} else {
			self.conditions.remove(&condition);
		}
	}

	fn format_tokens(&self, tokens: &Vec<Token>, f: &mut fmt::Formatter) -> fmt::Result {
		for token in tokens.iter() {
			let res = match token {
				&String(ref s) => f.buf.write_str(*s),

				&Placeholder(ref k) => {
					match self.content.find(k) {
						Some(value) => value.fmt(f),
						None => Ok(())
					}
				},

				&Conditional(ref k, expected, ref tokens) => {
					if self.conditions.contains(k) == expected {
						self.format_tokens(tokens, f)
					} else {
						Ok(())
					}
				}
			};

			match res {
				Err(e) => return Err(e),
				_ => {}
			}
		}

		Ok(())
	}
}

impl FromStr for Template {
	///Creates a new `Template` from a string.
	fn from_str(s: &str) -> Option<Template> {
		Some(Template::from_buffer(&mut BufReader::new(s.as_bytes())))
	}
}

impl fmt::Show for Template {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.format_tokens(&self.tokens, f)
	}
}

fn parse_block(b: &mut Buffer) -> Vec<Token> {
	let mut tokens = vec!();
	let mut parser = parse_string;

	loop {
		let ParserResult{token: token, next_parser: next} = parser(b);

		tokens.push(token);

		match next {
			Some(p) => parser = p,
			None => break
		}
	}

	tokens
}

fn parse_string(b: &mut Buffer) -> ParserResult {
	let mut content = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						content.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok('[') => {
				match b.read_char() {
					Ok('[') => {
						match b.read_char() {
							Ok(':') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_placeholder)
							},
							Ok('?') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_conditional)
							},
							Ok('/') => {
								skip_to_token_end(b);

								return ParserResult{
									token: String(content),
									next_parser: None
								}
							},
							Ok(c) => fail!("Unknown token type: '{}'", c),
							Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
							Err(e) => fail!("{}", e)
						}
					},
					Ok(c) => {
						content.push_char('[');
						content.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => content.push_char('['),
					Err(e) => fail!("{}", e)
				}
			},
			Ok(c) => content.push_char(c),
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: String(content),
		next_parser: None
	}
}

fn skip_to_token_end(b: &mut Buffer) {
	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(_) => {},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => break,
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e),
					_ => {}
				}
			},
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e),
			_ => {}
		}
	}
}

fn parse_placeholder(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Placeholder(label),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => label.push_char(']'),
					Err(e) => fail!("{}", e)
				}
			},
			Ok(c) => label.push_char(c),
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: Placeholder(label),
		next_parser: None
	}
}

fn parse_conditional(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";
	let mut expected = true;
	let mut expected_set = false;

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Conditional(label, expected, parse_block(b)),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => label.push_char(']'),
					Err(e) => fail!("{}", e)
				}
			},
			Ok('!') => {
				if label.len() == 0 && !expected_set {
					expected = false;
					expected_set = true;
				} else {
					label.push_char('!');
				}
			},
			Ok(c) => {
				label.push_char(c)
			},
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: Conditional(label, expected, vec!()),
		next_parser: None
	}
}

#[cfg(test)]
mod test {
	use super::{Template, Placeholder, String};

	#[test]
	fn basic_tokens() {
		let template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! This is a "));
		assert_eq!(template.tokens.get(3), &Placeholder(~"something"));
		assert_eq!(template.tokens.get(4), &String(~" template."));
	}

	#[test]
	#[should_fail]
	fn strange_tokens() {
		let _: Template = from_str("Hello, [[[:name]]]! This is a [[[[:something]] template.").unwrap();
	}

	#[test]
	fn escaped_tokens() {
		let template: Template = from_str("Hello, [[:name]]! Write placeholders like \\[[:this]] and escape them like \\\\\\[[:this]]").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! Write placeholders like [[:this]] and escape them like \\[[:this]]"));
	}

	#[test]
	fn replacement() {
		let mut template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		template.insert(~"name", ~("Peter"));
		template.insert(~"something", ~("nice"));
		assert_eq!(template.to_str(), ~"Hello, Peter! This is a nice template.");
	}

	#[test]
	fn templates_in_templates() {
		let mut template1: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		let mut template2: ~Template = ~from_str("really [[:something]]").unwrap();
		template1.insert(~"name", ~("Peter"));
		template2.insert(~"something", ~("nice"));

		template1.insert(~"something", template2);

		assert_eq!(template1.to_str(), ~"Hello, Peter! This is a really nice template.");
	}

	#[test]
	fn conditional() {
		let mut template: Template = from_str("Hello, [[:name]]![[?condition]] The condition is true.[[/condition]]").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter!");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}

	#[test]
	fn conditional_switch() {
		let mut template: Template = from_str("Hello, [[:name]]! The condition is [[?condition]]true[[/condition]][[?!condition]]false[[/condition]].").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is false.");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}
}<|endoftext|>


<commit_before>/*
 *           _           _            _             _          _
 *          /\ \        /\ \         /\ \     _    /\ \       /\ \
 *         /  \ \      /  \ \       /  \ \   /\_\ /  \ \      \_\ \
 *        / /\ \ \    / /\ \ \     / /\ \ \_/ / // /\ \ \     /\__ \
 *       / / /\ \_\  / / /\ \_\   / / /\ \___/ // / /\ \_\   / /_ \ \
 *      / / /_/ / / / /_/_ \/_/  / / /  \/____// /_/_ \/_/  / / /\ \ \
 *     / / /__\/ / / /____/\    / / /    / / // /____/\    / / /  \/_/
 *    / / /_____/ / /\____\/   / / /    / / // /\____\/   / / /
 *   / / /\ \ \  / / /______  / / /    / / // / /______  / / /
 *  / / /  \ \ \/ / /_______\/ / /    / / // / /_______\/_/ /
 *  \/_/    \_\/\/__________/\/_/     \/_/ \/__________/\_\/
 *
 *
 * This file is released under terms described in the LICENSE file at
 * the top directory of this repository.
 *
 * Please contact Mark McDermott <mark.elias.mcdermott@gmail.com> or
 * the current maintainer of this software if you do not have a copy of
 * the license file.
 *
 * -------------------------------------------------------------------
 *  REnet is a rust language wrapper for the ENet networking library
 *
 *  TODO List
 * -------------------------------------------------------------------
 */

extern crate libc;

use libc::{c_uint,c_void,size_t,c_int};

#[allow(non_snake_case)]
pub mod ffi;

pub fn initialize() -> Result<(), i32>  {
    unsafe {
        match ffi::enet_initialize() {
            0    => Ok(()),
            code => Err(code)
        }
    }
}

pub fn deinitialize() {
    unsafe {
        ffi::enet_deinitialize();
    }
}

pub fn linked_version() -> u32 {
    unsafe {
        ffi::enet_linked_version() as u32
    }
}

pub struct Host {
    ffi_handle : *mut c_void,
}

pub struct Peer {
    ffi_handle : *mut ffi::ENetPeer,
}

pub struct Packet {
    ffi_handle: *mut ffi::ENetPacket
}

/*
 * ------------------------------------------------------------------
 * Event: enum of event types*
 * ------------------------------------------------------------------
 */
pub enum Event {
    Connect(Peer),
    Receive(Peer,u8,Packet),
    Disconnect(Peer),
    None,
}

/*
 * ------------------------------------------------------------------
 * Host object: a wrapper around ENetHost*
 * ------------------------------------------------------------------
 */

impl Host {
    pub fn new_server(port: u16,
                      peer_count: u32,
                      channel_count: u32,
                      incoming_bandwidth: u32,
                      outgoing_bandwidth: u32) -> Result<Host, String> {
        let address = ffi::ENetAddress {
            host: ffi::ENET_HOST_ANY,
            port: port
        };

        let host_c = unsafe {
            ffi::enet_host_create(&address as *const ffi::ENetAddress,
                                  peer_count as size_t,
                                  channel_count as size_t,
                                  incoming_bandwidth as c_uint,
                                  outgoing_bandwidth as c_uint)
        };

        if host_c.is_null() {
            Err("Could not initialize host".to_string())
        } else {
            Ok(Host { ffi_handle: host_c })
        }
    }

    pub fn connect(timeout_ms: u32,
                   host_name: String,
                   port: u16,
                   channel_count: u32,
                   incoming_bandwidth: u32,
                   outgoing_bandwidth: u32) -> Result<(Host, Peer), String> {
        let host_c = unsafe {
            ffi::enet_host_create(std::ptr::null(),
                                  1, // 1 outgoing connection
                                  channel_count as size_t,
                                  incoming_bandwidth as c_uint,
                                  outgoing_bandwidth as c_uint)
        };

        if host_c.is_null() {
            return Err("Could not initialize host".to_string());
        }

        let host = Host { ffi_handle: host_c };
        let mut address = ffi::ENetAddress {
            host: 0,
            port: port
        };
        let host_name_c = std::ffi::CString::new(host_name).unwrap();

        let peer_c = unsafe {
            let address_ptr = &mut address as *mut ffi::ENetAddress;
            ffi::enet_address_set_host(address_ptr, host_name_c.as_ptr());
            ffi::enet_host_connect(host_c, address_ptr, channel_count as libc::size_t, 0)
        };

        if peer_c.is_null() {
            return Err("Could not initialize peer".to_string());
        }

        match host.service(timeout_ms) {
            Ok(Event::Connect(_)) =>
                Ok((host, Peer { ffi_handle: peer_c })),
            _ =>
                Err("Could not connect".to_string())
        }
    }

    pub fn service(&self, timeout_ms: u32) -> Result<Event, String> {
        let mut ffi_event = ffi::ENetEvent {
            etype: 0,
            peer: std::ptr::null_mut(),
            channelID: 0,
            data: 0,
            packet: std::ptr::null_mut()
        };

        let result: c_int = unsafe {
            let p_evt = &mut ffi_event as *mut _ as *mut c_void;
            ffi::enet_host_service(self.ffi_handle, p_evt, timeout_ms as c_uint)
        };

        if 0 > result {
            Err("Could not service the host".to_string())
        } else if 0 == result {
            Ok(Event::None)
        } else {
            let peer = Peer { ffi_handle: ffi_event.peer };

            match ffi_event.etype {
                ffi::ENET_EVENT_TYPE_CONNECT =>
                    Ok(Event::Connect(peer)),
                ffi::ENET_EVENT_TYPE_DISCONNECT =>
                    Ok(Event::Disconnect(peer)),
                ffi::ENET_EVENT_TYPE_RECEIVE => {
                    /*unsafe {
                        println!("receive {:?}", std::slice::from_raw_parts((*ffi_event.packet).data as *const u8,
                                                                            (*ffi_event.packet).dataLength as usize));
                    }*/
                    Ok(Event::Receive(peer, ffi_event.channelID,
                                      Packet { ffi_handle: ffi_event.packet }))
                }
                _ =>
                    Err("Invalid event".to_string())
            }
        }
    }

    pub fn flush(&self) {
        unsafe {
            ffi::enet_host_flush(self.ffi_handle)
        }
    }
}

impl Peer {
    pub fn send(&self, data: &[u8], flags: libc::c_uint, channel_id: u8) {
        unsafe {
            let data_ptr = data.as_ptr() as *mut libc::c_void; //repr.data as *mut libc::c_void;
            let data_len = data.len();//repr.len as libc::size_t;
            let packet = ffi::enet_packet_create(data_ptr, data_len, flags);
            ffi::enet_peer_send(self.ffi_handle, channel_id, packet);
        }
    }

    pub fn set_user_data(&self, data: *mut libc::c_void) {
        unsafe {
            (*self.ffi_handle).data = data;
        }
    }

    pub fn get_user_data(&self) -> *mut libc::c_void {
        unsafe {
            (*self.ffi_handle).data
        }
    }
}

impl Packet {
    pub fn data(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_parts((*self.ffi_handle).data as *const u8,
                (*self.ffi_handle).dataLength as usize)
        }
    }
}

impl Drop for Host {
    fn drop(&mut self) {
        unsafe { ffi::enet_host_destroy(self.ffi_handle); }
    }
}

impl Drop for Packet {
    fn drop(&mut self) {
        unsafe { ffi::enet_packet_destroy(self.ffi_handle); }
    }
}
<commit_msg>Remove old code, add cast<commit_after>/*
 *           _           _            _             _          _
 *          /\ \        /\ \         /\ \     _    /\ \       /\ \
 *         /  \ \      /  \ \       /  \ \   /\_\ /  \ \      \_\ \
 *        / /\ \ \    / /\ \ \     / /\ \ \_/ / // /\ \ \     /\__ \
 *       / / /\ \_\  / / /\ \_\   / / /\ \___/ // / /\ \_\   / /_ \ \
 *      / / /_/ / / / /_/_ \/_/  / / /  \/____// /_/_ \/_/  / / /\ \ \
 *     / / /__\/ / / /____/\    / / /    / / // /____/\    / / /  \/_/
 *    / / /_____/ / /\____\/   / / /    / / // /\____\/   / / /
 *   / / /\ \ \  / / /______  / / /    / / // / /______  / / /
 *  / / /  \ \ \/ / /_______\/ / /    / / // / /_______\/_/ /
 *  \/_/    \_\/\/__________/\/_/     \/_/ \/__________/\_\/
 *
 *
 * This file is released under terms described in the LICENSE file at
 * the top directory of this repository.
 *
 * Please contact Mark McDermott <mark.elias.mcdermott@gmail.com> or
 * the current maintainer of this software if you do not have a copy of
 * the license file.
 *
 * -------------------------------------------------------------------
 *  REnet is a rust language wrapper for the ENet networking library
 *
 *  TODO List
 * -------------------------------------------------------------------
 */

extern crate libc;

use libc::{c_uint,c_void,size_t,c_int};

#[allow(non_snake_case)]
pub mod ffi;

pub fn initialize() -> Result<(), i32>  {
    unsafe {
        match ffi::enet_initialize() {
            0    => Ok(()),
            code => Err(code)
        }
    }
}

pub fn deinitialize() {
    unsafe {
        ffi::enet_deinitialize();
    }
}

pub fn linked_version() -> u32 {
    unsafe {
        ffi::enet_linked_version() as u32
    }
}

pub struct Host {
    ffi_handle : *mut c_void,
}

pub struct Peer {
    ffi_handle : *mut ffi::ENetPeer,
}

pub struct Packet {
    ffi_handle: *mut ffi::ENetPacket
}

/*
 * ------------------------------------------------------------------
 * Event: enum of event types*
 * ------------------------------------------------------------------
 */
pub enum Event {
    Connect(Peer),
    Receive(Peer,u8,Packet),
    Disconnect(Peer),
    None,
}

/*
 * ------------------------------------------------------------------
 * Host object: a wrapper around ENetHost*
 * ------------------------------------------------------------------
 */

impl Host {
    pub fn new_server(port: u16,
                      peer_count: u32,
                      channel_count: u32,
                      incoming_bandwidth: u32,
                      outgoing_bandwidth: u32) -> Result<Host, String> {
        let address = ffi::ENetAddress {
            host: ffi::ENET_HOST_ANY,
            port: port
        };

        let host_c = unsafe {
            ffi::enet_host_create(&address as *const ffi::ENetAddress,
                                  peer_count as size_t,
                                  channel_count as size_t,
                                  incoming_bandwidth as c_uint,
                                  outgoing_bandwidth as c_uint)
        };

        if host_c.is_null() {
            Err("Could not initialize host".to_string())
        } else {
            Ok(Host { ffi_handle: host_c })
        }
    }

    pub fn connect(timeout_ms: u32,
                   host_name: String,
                   port: u16,
                   channel_count: u32,
                   incoming_bandwidth: u32,
                   outgoing_bandwidth: u32) -> Result<(Host, Peer), String> {
        let host_c = unsafe {
            ffi::enet_host_create(std::ptr::null(),
                                  1, // 1 outgoing connection
                                  channel_count as size_t,
                                  incoming_bandwidth as c_uint,
                                  outgoing_bandwidth as c_uint)
        };

        if host_c.is_null() {
            return Err("Could not initialize host".to_string());
        }

        let host = Host { ffi_handle: host_c };
        let mut address = ffi::ENetAddress {
            host: 0,
            port: port
        };
        let host_name_c = std::ffi::CString::new(host_name).unwrap();

        let peer_c = unsafe {
            let address_ptr = &mut address as *mut ffi::ENetAddress;
            ffi::enet_address_set_host(address_ptr, host_name_c.as_ptr());
            ffi::enet_host_connect(host_c, address_ptr, channel_count as libc::size_t, 0)
        };

        if peer_c.is_null() {
            return Err("Could not initialize peer".to_string());
        }

        match host.service(timeout_ms) {
            Ok(Event::Connect(_)) =>
                Ok((host, Peer { ffi_handle: peer_c })),
            _ =>
                Err("Could not connect".to_string())
        }
    }

    pub fn service(&self, timeout_ms: u32) -> Result<Event, String> {
        let mut ffi_event = ffi::ENetEvent {
            etype: 0,
            peer: std::ptr::null_mut(),
            channelID: 0,
            data: 0,
            packet: std::ptr::null_mut()
        };

        let result: c_int = unsafe {
            let p_evt = &mut ffi_event as *mut _ as *mut c_void;
            ffi::enet_host_service(self.ffi_handle, p_evt, timeout_ms as c_uint)
        };

        if 0 > result {
            Err("Could not service the host".to_string())
        } else if 0 == result {
            Ok(Event::None)
        } else {
            let peer = Peer { ffi_handle: ffi_event.peer };

            match ffi_event.etype {
                ffi::ENET_EVENT_TYPE_CONNECT =>
                    Ok(Event::Connect(peer)),
                ffi::ENET_EVENT_TYPE_DISCONNECT =>
                    Ok(Event::Disconnect(peer)),
                ffi::ENET_EVENT_TYPE_RECEIVE => {
                    Ok(Event::Receive(peer, ffi_event.channelID,
                                      Packet { ffi_handle: ffi_event.packet }))
                }
                _ =>
                    Err("Invalid event".to_string())
            }
        }
    }

    pub fn flush(&self) {
        unsafe {
            ffi::enet_host_flush(self.ffi_handle)
        }
    }
}

impl Peer {
    pub fn send(&self, data: &[u8], flags: libc::c_uint, channel_id: u8) {
        unsafe {
            let data_ptr = data.as_ptr() as *mut libc::c_void;
            let data_len = data.len() as libc::size_t;
            let packet = ffi::enet_packet_create(data_ptr, data_len, flags);
            ffi::enet_peer_send(self.ffi_handle, channel_id, packet);
        }
    }

    pub fn set_user_data(&self, data: *mut libc::c_void) {
        unsafe {
            (*self.ffi_handle).data = data;
        }
    }

    pub fn get_user_data(&self) -> *mut libc::c_void {
        unsafe {
            (*self.ffi_handle).data
        }
    }
}

impl Packet {
    pub fn data(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_parts((*self.ffi_handle).data as *const u8,
                (*self.ffi_handle).dataLength as usize)
        }
    }
}

impl Drop for Host {
    fn drop(&mut self) {
        unsafe { ffi::enet_host_destroy(self.ffi_handle); }
    }
}

impl Drop for Packet {
    fn drop(&mut self) {
        unsafe { ffi::enet_packet_destroy(self.ffi_handle); }
    }
}
<|endoftext|>


<commit_before>//! tomson provides conversions from Toml to Json and Json to Toml

extern crate toml;
extern crate rustc_serialize;

use rustc_serialize::json::{ self, ToJson };
use std::collections::BTreeMap;
use std::io::Read;

pub struct Json;

impl Json {
  /// Convert Json to Toml
  pub fn as_toml(read: &mut Read) -> Option<toml::Value> {
    let mut src = String::new();
    let _ = read.read_to_string(&mut src);
    let json = json::Json::from_str(&src);
    fn json_as_toml(value: &json::Json) -> toml::Value {
      match *value {
        json::Json::I64(ref v)     => toml::Value::Integer(v.clone()),
        json::Json::U64(ref v)     => toml::Value::Integer(v.clone() as i64),
        json::Json::F64(ref v)     => toml::Value::Float(v.clone()),
        json::Json::String(ref v)  => toml::Value::String(v.clone()),
        json::Json::Boolean(ref v) => toml::Value::Boolean(v.clone()),
        json::Json::Array(ref v)   => {
          let mut tl = Vec::<toml::Value>::new();
          for jv in v.iter() {
            tl.push(json_as_toml(jv));
          }
          toml::Value::Array(tl)
        },
        json::Json::Object(ref v)  => {
          let mut tm = BTreeMap::new();
          for (k,v) in v.iter() {
            tm.insert(k.clone(), json_as_toml(v));
          }
          toml::Value::Table(tm)
        },
        json::Json::Null           => toml::Value::String("".to_string())
      }
    }
    json.ok().map(|value| json_as_toml(&value))
  }
}

pub struct Toml;

impl Toml {
  /// Convert Toml to Json
  pub fn as_json(read: &mut Read) -> Option<json::Json> {
    let mut src = String::new();
    let _ = read.read_to_string(&mut src);
    let mut parser = toml::Parser::new(&src);

    fn value_as_json(toml: &toml::Value) -> json::Json {
      match *toml {
        toml::Value::Table(ref value)    => table_as_json(value),
        toml::Value::Array(ref array)    => {
          let mut vec = Vec::new();
          for value in array.iter() {
            vec.push(value_as_json(value));
          };
          vec.to_json()
        },
        toml::Value::String(ref value)   => value.to_json(),
        toml::Value::Integer(ref value)  => value.to_json(),
        toml::Value::Float(ref value)    => value.to_json(),
        toml::Value::Boolean(ref value)  => value.to_json(),
        toml::Value::Datetime(ref value) => value.to_json()
      }
    }

    fn table_as_json(table: &toml::Table) -> json::Json {
      let mut map = BTreeMap::new();
      for (k,v) in table.iter() {
        map.insert(k.to_string(), value_as_json(v));
      };
      map.to_json()
    }

    parser.parse().map(|tbl| table_as_json(&tbl))
  }
}

#[cfg(test)]
mod tests {
  use super::{ Json, Toml };
  use std::io::BufReader;
  #[test]
  fn test_to_json() {
    let mut reader = BufReader::new("[foo.bar]\n\nbaz=1".as_bytes());
    let res = Toml::as_json(&mut reader);
    assert_eq!(res.is_some(), true)
  }
  #[test]
  fn test_to_toml() {
    let mut reader = BufReader::new(r#"{"foo":1}"#.as_bytes());
    let res = Json::as_toml(&mut reader);
    assert_eq!(res.is_some(), true)
  }
}
<commit_msg>simplify<commit_after>//! tomson provides conversions from Toml to Json and Json to Toml

extern crate toml;
extern crate rustc_serialize;

use rustc_serialize::json::{ self, ToJson };
use std::collections::BTreeMap;
use std::io::Read;

pub struct Json;

impl Json {
  /// Convert Json to Toml
  pub fn as_toml(read: &mut Read) -> Option<toml::Value> {
    let mut src = String::new();
    let _ = read.read_to_string(&mut src);
    let json = json::Json::from_str(&src);
    fn adapt(value: &json::Json) -> toml::Value {
      match *value {
        json::Json::I64(ref v)     => toml::Value::Integer(v.clone()),
        json::Json::U64(ref v)     => toml::Value::Integer(v.clone() as i64),
        json::Json::F64(ref v)     => toml::Value::Float(v.clone()),
        json::Json::String(ref v)  => toml::Value::String(v.clone()),
        json::Json::Boolean(ref v) => toml::Value::Boolean(v.clone()),
        json::Json::Array(ref v)   => {
          let mut tl = Vec::<toml::Value>::new();
          for jv in v.iter() {
            tl.push(adapt(jv));
          }
          toml::Value::Array(tl)
        },
        json::Json::Object(ref v)  => {
          let mut tm = BTreeMap::new();
          for (k,v) in v.iter() {
            tm.insert(k.clone(), adapt(v));
          }
          toml::Value::Table(tm)
        },
        json::Json::Null           => toml::Value::String("".to_string())
      }
    }
    json.ok().map(|value| adapt(&value))
  }
}

pub struct Toml;

impl Toml {
  /// Convert Toml to Json
  pub fn as_json(read: &mut Read) -> Option<json::Json> {
    let mut src = String::new();
    let _ = read.read_to_string(&mut src);
    let mut parser = toml::Parser::new(&src);

    fn adapt(toml: &toml::Value) -> json::Json {
      match *toml {
        toml::Value::Table(ref value)    => {
          let mut map = BTreeMap::new();
          for (k,v) in value.iter() {
            map.insert(k.to_string(), adapt(v));
          };
          map.to_json()
        },
        toml::Value::Array(ref array)    => {
          let mut vec = Vec::new();
          for value in array.iter() {
            vec.push(adapt(value));
          };
          vec.to_json()
        },
        toml::Value::String(ref value)   => value.to_json(),
        toml::Value::Integer(ref value)  => value.to_json(),
        toml::Value::Float(ref value)    => value.to_json(),
        toml::Value::Boolean(ref value)  => value.to_json(),
        toml::Value::Datetime(ref value) => value.to_json()
      }
    }

    parser.parse().map(|value| adapt(&toml::Value::Table(value)))
  }
}

#[cfg(test)]
mod tests {
  use super::{ Json, Toml };
  use std::io::BufReader;
  #[test]
  fn test_to_json() {
    let mut reader = BufReader::new("[foo.bar]\n\nbaz=1".as_bytes());
    let res = Toml::as_json(&mut reader);
    assert_eq!(res.is_some(), true)
  }
  #[test]
  fn test_to_toml() {
    let mut reader = BufReader::new(r#"{"foo":1}"#.as_bytes());
    let res = Json::as_toml(&mut reader);
    assert_eq!(res.is_some(), true)
  }
}
<|endoftext|>


<commit_before>#![license = "MIT"]
#![deny(missing_docs)]
#![feature(unsafe_destructor)]

//! A library for setting current values for stack scope,
//! such as application structure.

pub use current::{ Current, CurrentGuard };

use std::cell::RefCell;

mod current;

/// Specifies whether to use a shared reference,
/// or the current object of that type.
pub enum Usage<'a, T: 'a> {
    /// Use a shared reference.
    Use(&'a RefCell<T>),
    /// Use the current object.
    UseCurrent,
}

impl<'a, T: 'a> Usage<'a, T> {
    /// Calls closure with a shared reference to used object.
    pub fn with<U>(&self, f: |&RefCell<T>| -> U) -> Option<U> {
        match *self {
            Use(val) => Some(f(val)),
            UseCurrent => Current::with_current(f),
        }
    }

    /// Calls closure with a shared reference to used object.
    /// Gives a nicer error message if current object is not set.
    pub fn with_unwrap<U>(&self, f: |&RefCell<T>| -> U) -> U {
        match *self {
            Use(val) => f(val),
            UseCurrent => Current::with_current_unwrap(f),
        }
    }

    /// Unwraps to the scope of usage.
    /// Should only be called when the usage object or returned reference
    /// does not outlives the guard of the current object.
    #[inline(always)]
    pub unsafe fn unsafe_unwrap(&self) -> &RefCell<T> {
        match *self {
            Use(val) => val,
            UseCurrent => {
                Current::with_current_unwrap(|current: &RefCell<T>| {
                    use std::mem::transmute;
                    transmute(current)
                })
            }
        }
    }
}

impl<'a, T: Get<U>, U> Get<U> for Usage<'a, T> {
    #[inline(always)]
    fn get(&self) -> U {
        self.with_unwrap(|val: &RefCell<T>| {
            val.borrow().deref().get()
        })
    }
}

impl<'a, F, T: Modifier<F>> Modifier<Usage<'a, F>> for T {
    #[inline(always)]
    fn modify(self, obj: &mut Usage<'a, F>) {
        unsafe {
            let val: &RefCell<F> = obj.unsafe_unwrap();
            self.modify(val.borrow_mut().deref_mut())
        }
    }
}

impl<'a, T: Get<U>, U> Get<U> for &'a RefCell<T> {
    #[inline(always)]
    fn get(&self) -> U {
        self.borrow().deref().get()
    }
}

impl<'a, F, T: Modifier<F>> Modifier<&'a RefCell<F>> for T {
    #[inline(always)]
    fn modify(self, obj: &mut &'a RefCell<F>) {
        self.modify(obj.borrow_mut().deref_mut())
    }
}

/// Allows use of the implemented type as an argument to Set::set.
///
/// This allows types to be used for ad-hoc overloading of Set::set
/// to perform complex updates to the parameter of Modifier.
pub trait Modifier<F> {
    /// Modify `F` with self.
    fn modify(self, &mut F);
}

/// A blanket trait providing the set and set_mut methods for all types.
pub trait Set<M: Modifier<Self>> {
    /// Modify self using the provided modifier.
    #[inline(always)]
    fn set(mut self, modifier: M) -> Self {
        modifier.modify(&mut self);
        self
    }

    /// Modify self through a mutable reference with the provided modifier.
    #[inline(always)]
    fn set_mut(&mut self, modifier: M) -> &mut Self {
        modifier.modify(self);
        self
    }
}

impl<T, U: Modifier<T>> Set<U> for T {}

/// Implemented by types that can be constructed from another value.
pub trait Get<T> {
    /// Returns new value.
    fn get(&self) -> T;
}

/// Transmutes the current value to a lifetime scope.
/// The scope must not outlive the guard.
/// This is used to work around issues with closure that require move by value.
pub unsafe fn unsafe_current_unwrap<T>(_scope: &()) -> &T {
    Current::with_current_unwrap(|current: &T| {
        use std::mem::transmute;
        transmute(current)
    })
}

/// Sets value on current type, assuming using a `RefCell` to make it safe.
/// Panics if there is no current object of type `T`.
pub fn set<T, U: Modifier<T>>(val: U) {
    let scope = &();
    let current: &RefCell<T> = unsafe { unsafe_current_unwrap(scope) };
    val.modify(&mut*current.borrow_mut());
}

/// Gets value from current object of type `T`.
/// The returned type must implement the `GetFrom` trait.
pub fn get<T: Get<U>, U>() -> U {
    Current::with_current_unwrap(|current: &RefCell<T>| {
        match current.try_borrow() {
            Some(val) => val.get(),
            None => {
                use std::intrinsics::get_tydesc;
                let name = unsafe { (*get_tydesc::<T>()).name };
                panic!("The current `{}` is already in use", name);
            }
        }
    })
}
<commit_msg>Got rid of Modifier constraint on Set<commit_after>#![license = "MIT"]
#![deny(missing_docs)]
#![feature(unsafe_destructor)]

//! A library for setting current values for stack scope,
//! such as application structure.

pub use current::{ Current, CurrentGuard };

use std::cell::RefCell;

mod current;

/// Specifies whether to use a shared reference,
/// or the current object of that type.
pub enum Usage<'a, T: 'a> {
    /// Use a shared reference.
    Use(&'a RefCell<T>),
    /// Use the current object.
    UseCurrent,
}

impl<'a, T: 'a> Usage<'a, T> {
    /// Calls closure with a shared reference to used object.
    pub fn with<U>(&self, f: |&RefCell<T>| -> U) -> Option<U> {
        match *self {
            Use(val) => Some(f(val)),
            UseCurrent => Current::with_current(f),
        }
    }

    /// Calls closure with a shared reference to used object.
    /// Gives a nicer error message if current object is not set.
    pub fn with_unwrap<U>(&self, f: |&RefCell<T>| -> U) -> U {
        match *self {
            Use(val) => f(val),
            UseCurrent => Current::with_current_unwrap(f),
        }
    }

    /// Unwraps to the scope of usage.
    /// Should only be called when the usage object or returned reference
    /// does not outlives the guard of the current object.
    #[inline(always)]
    pub unsafe fn unsafe_unwrap(&self) -> &RefCell<T> {
        match *self {
            Use(val) => val,
            UseCurrent => {
                Current::with_current_unwrap(|current: &RefCell<T>| {
                    use std::mem::transmute;
                    transmute(current)
                })
            }
        }
    }
}

impl<'a, T: Get<U>, U> Get<U> for Usage<'a, T> {
    #[inline(always)]
    fn get(&self) -> U {
        self.with_unwrap(|val: &RefCell<T>| {
            val.borrow().deref().get()
        })
    }
}

impl<'a, F, T: Modifier<F>> Modifier<Usage<'a, F>> for T {
    #[inline(always)]
    fn modify(self, obj: &mut Usage<'a, F>) {
        unsafe {
            let val: &RefCell<F> = obj.unsafe_unwrap();
            self.modify(val.borrow_mut().deref_mut())
        }
    }
}

impl<'a, T: Get<U>, U> Get<U> for &'a RefCell<T> {
    #[inline(always)]
    fn get(&self) -> U {
        self.borrow().deref().get()
    }
}

impl<'a, F, T: Modifier<F>> Modifier<&'a RefCell<F>> for T {
    #[inline(always)]
    fn modify(self, obj: &mut &'a RefCell<F>) {
        self.modify(obj.borrow_mut().deref_mut())
    }
}

/// Allows use of the implemented type as an argument to Set::set.
///
/// This allows types to be used for ad-hoc overloading of Set::set
/// to perform complex updates to the parameter of Modifier.
pub trait Modifier<F> {
    /// Modify `F` with self.
    fn modify(self, &mut F);
}

/// A blanket trait providing the set and set_mut methods for all types.
pub trait Set<M> {
    /// Modify self using the provided modifier.
    fn set(mut self, modifier: M) -> Self;

    /// Modify self through a mutable reference with the provided modifier.
    fn set_mut(&mut self, modifier: M) -> &mut Self;
}

impl<T, U: Modifier<T>> Set<U> for T {
    #[inline(always)]
    fn set(mut self, modifier: U) -> T {
        modifier.modify(&mut self);
        self
    }

    #[inline(always)]
    fn set_mut(&mut self, modifier: U) -> &mut T {
        modifier.modify(self);
        self
    }
}

/// Implemented by types that can be constructed from another value.
pub trait Get<T> {
    /// Returns new value.
    fn get(&self) -> T;
}

/// Transmutes the current value to a lifetime scope.
/// The scope must not outlive the guard.
/// This is used to work around issues with closure that require move by value.
pub unsafe fn unsafe_current_unwrap<T>(_scope: &()) -> &T {
    Current::with_current_unwrap(|current: &T| {
        use std::mem::transmute;
        transmute(current)
    })
}

/// Sets value on current type, assuming using a `RefCell` to make it safe.
/// Panics if there is no current object of type `T`.
pub fn set<T, U: Modifier<T>>(val: U) {
    let scope = &();
    let current: &RefCell<T> = unsafe { unsafe_current_unwrap(scope) };
    val.modify(&mut*current.borrow_mut());
}

/// Gets value from current object of type `T`.
/// The returned type must implement the `GetFrom` trait.
pub fn get<T: Get<U>, U>() -> U {
    Current::with_current_unwrap(|current: &RefCell<T>| {
        match current.try_borrow() {
            Some(val) => val.get(),
            None => {
                use std::intrinsics::get_tydesc;
                let name = unsafe { (*get_tydesc::<T>()).name };
                panic!("The current `{}` is already in use", name);
            }
        }
    })
}
<|endoftext|>


<commit_before>extern crate image;
extern crate bitreader;

use std::path::Path;
use std::fs::File;

use image::*;

use bitreader::BitReader;

pub struct StegObject {
    cover_image: DynamicImage
}

impl StegObject
{
    pub fn new(file_path: &str) -> StegObject {
        StegObject {
            cover_image: image::open(&Path::new(&file_path)).unwrap()
        }
    }

    pub fn encode_with(&mut self, message: &str) {
        let bit_vector = get_bit_vec(message);

        encode(&mut self.cover_image, &bit_vector);

        let ref mut fout = File::create(&Path::new("/home/hugh/Pictures/yurt.png")).unwrap();

        let _ = self.cover_image.save(fout, ImageFormat::PNG).unwrap();
    }
}

// Get a Vector of Bits to Encode the Image with
fn get_bit_vec(message: &str) -> Vec<u8> {
    let mut bit_vector = Vec::new();
    let mut reader = BitReader::new(&message.as_bytes());

    // Multipled by 8 because it's a Vec of bits not bytes
    for _ in 0..message.len() * 8 {
        bit_vector.push(reader.read_u8(1).unwrap());
    }

    bit_vector
}

// Encode the Image with the Vector of Bits
fn encode(c_image: &mut DynamicImage, bit_vec: &Vec<u8>) {
    let (width, height) = c_image.dimensions();

    let mut img = c_image.as_mut_rgb8().unwrap();

    let mut index = 0;

    'outer: for y_co_ord in 0..height {
        for x_co_ord in 0..width {
            let pixel = img.get_pixel_mut(x_co_ord, y_co_ord);

            for channel in 0..3 {
                if index >= bit_vec.len() {
                    println!("{}", pixel.data[1]);
                    break 'outer;
                }

                pixel.data[channel] = (pixel.data[channel] & 0xFE) | bit_vec[index];

                index += 1;
            }
        }
    }
}

/***************************************************************************************************
 *                                                                                *
 *                                         Tests                                                   *
 *                                                                                *
 ***************************************************************************************************/

#[test]
fn test_get_bit_vec_len() {
    let bits = get_bit_vec("h");

    assert_eq!(8, bits.len());
}

#[test]
fn test_get_bit_vec() {
    let test_bits = vec![0, 1, 1, 0, 1, 0, 0, 0];
    let bits = get_bit_vec("h");

    assert_eq!(bits, test_bits);
}

#[test]
fn test_encode_red_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img.as_mut_rgb8().unwrap(), &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[0] % 2, bit_vec[0]);
}

#[test]
fn test_encode_green_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img.as_mut_rgb8().unwrap(), &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[1] % 2, bit_vec[1]);
}

#[test]
fn test_encode_blue_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img.as_mut_rgb8().unwrap(), &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[2] % 2 as u8, bit_vec[2]);
}

#[test]
fn test_full_byte_is_encoded() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let mut encoded_bit_vec = Vec::new();
    let mut count = 0;

    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img.as_mut_rgb8().unwrap(), &bit_vec);

    'outer: for x_co_ord in 0..3 {
        let pixel = img.get_pixel(x_co_ord, 0);

        for channel in 0..3 {
            if count >= 8 {
                break 'outer;
            }

            encoded_bit_vec.push(pixel.data[channel] % 2);

            count += 1;
        }
    }

    assert_eq!(encoded_bit_vec, bit_vec);
}

<commit_msg>Chaned 'use image::' so it doesn't import everything<commit_after>extern crate image;
extern crate bitreader;

use std::path::Path;
use std::fs::File;

use image::{DynamicImage, GenericImage, ImageFormat};

use bitreader::BitReader;

pub struct StegObject {
    cover_image: DynamicImage
}

impl StegObject
{
    pub fn new(file_path: &str) -> StegObject {
        StegObject {
            cover_image: image::open(&Path::new(&file_path)).unwrap()
        }
    }

    pub fn encode_with(&mut self, message: &str) {
        let bit_vector = get_bit_vec(message);

        encode(&mut self.cover_image, &bit_vector);

        let ref mut fout = File::create(&Path::new("/home/hugh/Pictures/yurt.png")).unwrap();

        let _ = self.cover_image.save(fout, ImageFormat::PNG).unwrap();
    }
}

// Get a Vector of Bits to Encode the Image with
fn get_bit_vec(message: &str) -> Vec<u8> {
    let mut bit_vector = Vec::new();
    let mut reader = BitReader::new(&message.as_bytes());

    // Multipled by 8 because it's a Vec of bits not bytes
    for _ in 0..message.len() * 8 {
        bit_vector.push(reader.read_u8(1).unwrap());
    }

    bit_vector
}

// Encode the Image with the Vector of Bits
fn encode(c_image: &mut DynamicImage, bit_vec: &Vec<u8>) {
    let (width, height) = c_image.dimensions();

    let mut img = c_image.as_mut_rgb8().unwrap();

    let mut index = 0;

    'outer: for y_co_ord in 0..height {
        for x_co_ord in 0..width {
            let pixel = img.get_pixel_mut(x_co_ord, y_co_ord);

            for channel in 0..3 {
                if index >= bit_vec.len() {
                    println!("{}", pixel.data[1]);
                    break 'outer;
                }

                pixel.data[channel] = (pixel.data[channel] & 0xFE) | bit_vec[index];

                index += 1;
            }
        }
    }
}

/***************************************************************************************************
 *                                                                                *
 *                                         Tests                                                   *
 *                                                                                *
 ***************************************************************************************************/

#[test]
fn test_get_bit_vec_len() {
    let bits = get_bit_vec("h");

    assert_eq!(8, bits.len());
}

#[test]
fn test_get_bit_vec() {
    let test_bits = vec![0, 1, 1, 0, 1, 0, 0, 0];
    let bits = get_bit_vec("h");

    assert_eq!(bits, test_bits);
}

#[test]
fn test_encode_red_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img.as_mut_rgb8().unwrap(), &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[0] % 2, bit_vec[0]);
}

#[test]
fn test_encode_green_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img.as_mut_rgb8().unwrap(), &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[1] % 2, bit_vec[1]);
}

#[test]
fn test_encode_blue_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img.as_mut_rgb8().unwrap(), &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[2] % 2 as u8, bit_vec[2]);
}

#[test]
fn test_full_byte_is_encoded() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let mut encoded_bit_vec = Vec::new();
    let mut count = 0;

    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img.as_mut_rgb8().unwrap(), &bit_vec);

    'outer: for x_co_ord in 0..3 {
        let pixel = img.get_pixel(x_co_ord, 0);

        for channel in 0..3 {
            if count >= 8 {
                break 'outer;
            }

            encoded_bit_vec.push(pixel.data[channel] % 2);

            count += 1;
        }
    }

    assert_eq!(encoded_bit_vec, bit_vec);
}

<|endoftext|>


<commit_before>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::min;
use score::Score;
use sorted_result_set::SortedResultSet;
use std::ascii::AsciiExt;

#[derive(Debug)]
pub struct Search {
    pub config: Configuration,
    current: usize,
    pub query: String,
    pub selection: Option<String>,
    pub result: Vec<String>,
    done: bool,
}

impl Search {
    pub fn blank(config: Configuration) -> Search {
        let query = config.initial_search.clone();
        let previous_result = config.choices.clone();
        Search::new(config, query, previous_result, 0, false)
    }

    pub fn is_done(&self) -> bool {
        self.done
    }

    pub fn done(self) -> Search {
        Search::new(self.config, self.query, self.result, self.current, true)
    }

    fn new(config: Configuration, query: String, result: Vec<String>, index: usize, done: bool) -> Search {

        let selection = Search::select(&result, index);

        Search { config: config,
                 current: index,
                 query: query,
                 selection: selection,
                 result: result,
                 done: done}
    }

    fn new_for_index(self, index: usize) -> Search {
        Search::new(self.config, self.query, self.result, index, self.done)
    }

    fn new_for_query(self, new_query: String) -> Search {
        let new_result = Search::filter(new_query.as_slice(), &self.config.choices);

        Search::new(self.config, new_query, new_result, 0, self.done)
    }

    pub fn filter(query: &str, choices: &Vec<String>) -> Vec<String> {
        let mut results = SortedResultSet::new(20);
        let query = query.to_ascii_lowercase();

        for choice in choices.iter() {
            let choice = choice.to_ascii_lowercase();

            match Score::score(choice.as_slice(), query.as_slice()) {
                0.0     => continue,
                quality => results.push(quality,choice.clone()),
            };
        }
        results.sorted_vec()
    }

    fn select(result: &Vec<String>, index: usize) -> Option<String> {
        if result.len() > 0 {
            Some(result[index].to_string())
        } else {
            None
        }
    }

    pub fn down(self) -> Search {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    pub fn up(self) -> Search {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    pub fn append_to_search(self, input: &str) -> Search {
        let mut new_query = self.query.clone();
        new_query.push_str(input.as_slice());

        self.new_for_query(new_query)
    }

    pub fn backspace(self) -> Search {
        let mut new_query = self.query.clone();
        new_query.pop();

        self.new_for_query(new_query)
    }

    fn next_index(&self) -> usize {
        let next_index = self.current + 1;

        if next_index >= self.actual_limit() {
            0
        } else {
            next_index
        }
    }

    fn prev_index(&self) -> usize {
        if self.current == 0 {
            self.actual_limit() - 1
        } else {
            self.current - 1
        }
    }

    fn actual_limit(&self) -> usize {
        min(self.config.visible_limit, self.result.len())
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use configuration::Configuration;
    use super::*;
    use self::test::Bencher;

    fn one_two_three() -> Vec<String> {
        vec!["one".to_string(),
             "two".to_string(),
             "three".to_string()]
    }

    #[test]
    fn it_selects_the_first_choice_by_default() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn it_selets_the_second_when_down_is_called() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_end_of_list() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.down().down().down().down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_top_of_list() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.up().up().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_visible_limit() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, Some(2));
        let search = Search::blank(config);

        assert_eq!(search.down().down().down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.append_to_search("t").down().selection, Some("three".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results_twice() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.append_to_search("t").append_to_search("w").selection, Some("two".to_string()));
    }

    #[test]
    fn it_handles_not_matching_anything() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.append_to_search("x").selection, None);
    }

    #[test]
    fn up_match_nothing_after_filtering_all_out() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("x");

        assert_eq!(search.up().selection, None);
    }

    #[test]
    fn down_match_nothing_after_filtering_all_out() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("x");

        assert_eq!(search.down().selection, None);
    }

    #[test]
    fn backspaces_over_characters() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("e");

        assert_eq!(search.query, "e");
        assert_eq!(search.backspace().query, "");
    }

    #[test]
    fn resets_the_index_when_removing_char_from_search() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("e");

        assert_eq!(search.down().backspace().current, 0);
    }

    #[test]
    fn resets_the_index_when_adding_char_to_seach() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).down();

        assert_eq!(search.append_to_search("o").current, 0);
    }

    #[test]
    fn previous_results_appear_after_backspace() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("t");

        assert_eq!(search.backspace().result.len(), 3);
    }

    #[test]
    fn initial_search_is_not_done() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert!(!search.is_done());
    }

    #[test]
    fn done_search_is_done() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).done();

        assert!(search.is_done());
    }

    #[test]
    fn done_search_has_selection() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).done();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_bottom_of_choices() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("n").down();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_top_of_choices() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("n").up();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn search_is_case_insensitive() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("T");

        assert_eq!(search.result.len(), 2);
    }

    fn input_times(n: usize) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for thing in one_two_three().iter().cycle().take(n) {
            result.push(thing.clone());
        }
        result
    }

    //84114 ns/iter (+/- 33515)
    #[bench]
    fn filter_speed(b: &mut Bencher) {
        let input = input_times(1000);
        let query = "t";

        b.iter(||{
            Search::filter(query, &input)
        });
    }
}
<commit_msg>doesn't shadow variable<commit_after>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::min;
use score::Score;
use sorted_result_set::SortedResultSet;
use std::ascii::AsciiExt;

#[derive(Debug)]
pub struct Search {
    pub config: Configuration,
    current: usize,
    pub query: String,
    pub selection: Option<String>,
    pub result: Vec<String>,
    done: bool,
}

impl Search {
    pub fn blank(config: Configuration) -> Search {
        let query = config.initial_search.clone();
        let previous_result = config.choices.clone();
        Search::new(config, query, previous_result, 0, false)
    }

    pub fn is_done(&self) -> bool {
        self.done
    }

    pub fn done(self) -> Search {
        Search::new(self.config, self.query, self.result, self.current, true)
    }

    fn new(config: Configuration, query: String, result: Vec<String>, index: usize, done: bool) -> Search {

        let selection = Search::select(&result, index);

        Search { config: config,
                 current: index,
                 query: query,
                 selection: selection,
                 result: result,
                 done: done}
    }

    fn new_for_index(self, index: usize) -> Search {
        Search::new(self.config, self.query, self.result, index, self.done)
    }

    fn new_for_query(self, new_query: String) -> Search {
        let new_result = Search::filter(new_query.as_slice(), &self.config.choices);

        Search::new(self.config, new_query, new_result, 0, self.done)
    }

    pub fn filter(query: &str, choices: &Vec<String>) -> Vec<String> {
        let mut results = SortedResultSet::new(20);
        let query = query.to_ascii_lowercase();

        for choice in choices.iter() {
            let lower_choice = choice.to_ascii_lowercase();

            match Score::score(lower_choice.as_slice(), query.as_slice()) {
                0.0     => continue,
                quality => results.push(quality,choice.clone()),
            };
        }
        results.sorted_vec()
    }

    fn select(result: &Vec<String>, index: usize) -> Option<String> {
        if result.len() > 0 {
            Some(result[index].to_string())
        } else {
            None
        }
    }

    pub fn down(self) -> Search {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    pub fn up(self) -> Search {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    pub fn append_to_search(self, input: &str) -> Search {
        let mut new_query = self.query.clone();
        new_query.push_str(input.as_slice());

        self.new_for_query(new_query)
    }

    pub fn backspace(self) -> Search {
        let mut new_query = self.query.clone();
        new_query.pop();

        self.new_for_query(new_query)
    }

    fn next_index(&self) -> usize {
        let next_index = self.current + 1;

        if next_index >= self.actual_limit() {
            0
        } else {
            next_index
        }
    }

    fn prev_index(&self) -> usize {
        if self.current == 0 {
            self.actual_limit() - 1
        } else {
            self.current - 1
        }
    }

    fn actual_limit(&self) -> usize {
        min(self.config.visible_limit, self.result.len())
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use configuration::Configuration;
    use super::*;
    use self::test::Bencher;

    fn one_two_three() -> Vec<String> {
        vec!["one".to_string(),
             "two".to_string(),
             "three".to_string()]
    }

    #[test]
    fn it_selects_the_first_choice_by_default() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn it_selets_the_second_when_down_is_called() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_end_of_list() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.down().down().down().down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_top_of_list() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.up().up().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_visible_limit() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, Some(2));
        let search = Search::blank(config);

        assert_eq!(search.down().down().down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.append_to_search("t").down().selection, Some("three".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results_twice() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.append_to_search("t").append_to_search("w").selection, Some("two".to_string()));
    }

    #[test]
    fn it_handles_not_matching_anything() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert_eq!(search.append_to_search("x").selection, None);
    }

    #[test]
    fn up_match_nothing_after_filtering_all_out() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("x");

        assert_eq!(search.up().selection, None);
    }

    #[test]
    fn down_match_nothing_after_filtering_all_out() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("x");

        assert_eq!(search.down().selection, None);
    }

    #[test]
    fn backspaces_over_characters() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("e");

        assert_eq!(search.query, "e");
        assert_eq!(search.backspace().query, "");
    }

    #[test]
    fn resets_the_index_when_removing_char_from_search() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("e");

        assert_eq!(search.down().backspace().current, 0);
    }

    #[test]
    fn resets_the_index_when_adding_char_to_seach() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).down();

        assert_eq!(search.append_to_search("o").current, 0);
    }

    #[test]
    fn previous_results_appear_after_backspace() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("t");

        assert_eq!(search.backspace().result.len(), 3);
    }

    #[test]
    fn initial_search_is_not_done() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config);

        assert!(!search.is_done());
    }

    #[test]
    fn done_search_is_done() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).done();

        assert!(search.is_done());
    }

    #[test]
    fn done_search_has_selection() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).done();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_bottom_of_choices() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("n").down();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_top_of_choices() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("n").up();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn search_is_case_insensitive() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(config).append_to_search("T");

        assert_eq!(search.result.len(), 2);
    }

    fn input_times(n: usize) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for thing in one_two_three().iter().cycle().take(n) {
            result.push(thing.clone());
        }
        result
    }

    //84114 ns/iter (+/- 33515)
    #[bench]
    fn filter_speed(b: &mut Bencher) {
        let input = input_times(1000);
        let query = "t";

        b.iter(||{
            Search::filter(query, &input)
        });
    }
}
<|endoftext|>