<commit_before>//! Print the contents of font tables.
//!
//! This accepts command line arguments similar to what is present in ttx,
//! although it does not produce xml output.

use std::{collections::HashSet, str::FromStr};

use font_types::Tag;
use read_fonts::{traversal::SomeTable, FileRef, FontData, FontRef, ReadError, TableProvider};

mod print;
mod query;

use print::PrettyPrinter;
use query::Query;

fn main() -> Result<(), Error> {
    let args = flags::Args::from_env().map_err(|e| Error(e.to_string()))?;
    let bytes = std::fs::read(&args.input).unwrap();
    let data = FontData::new(&bytes);
    let font = FileRef::new(data)
        .unwrap()
        .fonts()
        .nth(args.index.unwrap_or(0) as usize)
        .unwrap()
        .unwrap();
    if args.list {
        list_tables(&font);
        return Ok(());
    }

    if let Some(query) = &args.query {
        return query::print_query(&font, query).map_err(Error);
    }

    let filter = TableFilter::from_args(&args)?;
    print_tables(&font, &filter);
    Ok(())
}

fn list_tables(font: &FontRef) {
    println!("Tag  Offset  Length  Checksum");
    println!("-------------------------------");

    let offset_pad = get_offset_width(font);

    for record in font.table_directory.table_records() {
        println!(
            "{0} 0x{1:02$X} {3:8} 0x{4:08X} ",
            record.tag(),
            record.offset().to_u32(),
            offset_pad,
            record.length(),
            record.checksum()
        );
    }
}

fn print_tables(font: &FontRef, filter: &TableFilter) {
    let mut printed = HashSet::new();
    for tag in font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.tag())
        .filter(|tag| filter.should_print(*tag))
    {
        printed.insert(tag);
        print_table(font, tag)
    }

    if let TableFilter::Include(to_print) = filter {
        for unprinted in to_print.difference(&printed) {
            println!("Table {unprinted} not found");
        }
    }
}

fn get_offset_width(font: &FontRef) -> usize {
    // pick how much padding we use for offsets based on the max offset in directory
    let max_off = font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.offset().to_u32())
        .max()
        .unwrap_or_default();
    hex_width(max_off)
}

/// Return the number of hex digits required to represent a given number.
fn hex_width(val: u32) -> usize {
    match val {
        0..=0xffff => 4usize,
        0x10000..=0xffff_ff => 6,
        0x1000000.. => 8,
    }
}

/// Given a font and a tag, return the appropriate table as a [`dyn SomeTable`][SomeTable].
fn get_some_table<'a>(
    font: &FontRef<'a>,
    tag: Tag,
) -> Result<Box<dyn SomeTable<'a> + 'a>, ReadError> {
    match tag {
        read_fonts::tables::gpos::TAG => font.gpos().map(|x| Box::new(x) as _),
        read_fonts::tables::gsub::TAG => font.gsub().map(|x| Box::new(x) as _),
        read_fonts::tables::cmap::TAG => font.cmap().map(|x| Box::new(x) as _),
        read_fonts::tables::gdef::TAG => font.gdef().map(|x| Box::new(x) as _),
        read_fonts::tables::glyf::TAG => font.glyf().map(|x| Box::new(x) as _),
        read_fonts::tables::head::TAG => font.head().map(|x| Box::new(x) as _),
        read_fonts::tables::hhea::TAG => font.hhea().map(|x| Box::new(x) as _),
        read_fonts::tables::hmtx::TAG => font.hmtx().map(|x| Box::new(x) as _),
        read_fonts::tables::loca::TAG => font.loca(None).map(|x| Box::new(x) as _),
        read_fonts::tables::maxp::TAG => font.maxp().map(|x| Box::new(x) as _),
        read_fonts::tables::name::TAG => font.name().map(|x| Box::new(x) as _),
        read_fonts::tables::post::TAG => font.post().map(|x| Box::new(x) as _),
        read_fonts::tables::colr::TAG => font.colr().map(|x| Box::new(x) as _),
        read_fonts::tables::stat::TAG => font.stat().map(|x| Box::new(x) as _),
        _ => Err(ReadError::TableIsMissing(tag)),
    }
}

fn print_table(font: &FontRef, tag: Tag) {
    match get_some_table(font, tag) {
        Ok(table) => fancy_print_table(&table).unwrap(),
        Err(err) => println!("{tag}: Error '{err}'"),
    }
}

enum TableFilter {
    All,
    Include(HashSet<Tag>),
    Exclude(HashSet<Tag>),
}

impl TableFilter {
    fn from_args(args: &flags::Args) -> Result<Self, Error> {
        if args.tables.is_some() && args.exclude.is_some() {
            return Err(Error::new("pass only one of --tables and --exclude"));
        }
        if let Some(tags) = &args.tables {
            make_tag_set(tags).map(TableFilter::Include)
        } else if let Some(tags) = &args.exclude {
            make_tag_set(tags).map(TableFilter::Exclude)
        } else {
            Ok(TableFilter::All)
        }
    }

    fn should_print(&self, tag: Tag) -> bool {
        match self {
            TableFilter::All => true,
            TableFilter::Include(tags) => tags.contains(&tag),
            TableFilter::Exclude(tags) => !tags.contains(&tag),
        }
    }
}

fn make_tag_set(inp: &str) -> Result<HashSet<Tag>, Error> {
    inp.split(' ')
        .map(|raw| match Tag::from_str(raw) {
            Ok(tag) => Ok(tag),
            Err(e) => Err(Error(format!(
                "Invalid tag '{}': {e}",
                raw.escape_default()
            ))),
        })
        .collect()
}

#[derive(Debug, Clone)]
struct Error(String);

impl Error {
    fn new(t: impl std::fmt::Display) -> Self {
        Self(t.to_string())
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

impl std::error::Error for Error {}

fn fancy_print_table<'a>(table: &(dyn SomeTable<'a> + 'a)) -> std::io::Result<()> {
    let stdout = std::io::stdout();
    let mut locked = stdout.lock();
    let mut formatter = PrettyPrinter::new(&mut locked);
    formatter.print_root_table(table)
}

mod flags {
    use super::Query;
    use std::path::PathBuf;

    xflags::xflags! {
        /// Generate font table representations
        cmd args
            required input: PathBuf
            {
                optional -i, --index index: u32
                optional -l, --list
                optional -q, --query query: Query
                optional -t, --tables include: String
                optional -x, --exclude exclude: String
            }

    }
}
<commit_msg>add vmtx and vhea to otexplorer<commit_after>//! Print the contents of font tables.
//!
//! This accepts command line arguments similar to what is present in ttx,
//! although it does not produce xml output.

use std::{collections::HashSet, str::FromStr};

use font_types::Tag;
use read_fonts::{traversal::SomeTable, FileRef, FontData, FontRef, ReadError, TableProvider};

mod print;
mod query;

use print::PrettyPrinter;
use query::Query;

fn main() -> Result<(), Error> {
    let args = flags::Args::from_env().map_err(|e| Error(e.to_string()))?;
    let bytes = std::fs::read(&args.input).unwrap();
    let data = FontData::new(&bytes);
    let font = FileRef::new(data)
        .unwrap()
        .fonts()
        .nth(args.index.unwrap_or(0) as usize)
        .unwrap()
        .unwrap();
    if args.list {
        list_tables(&font);
        return Ok(());
    }

    if let Some(query) = &args.query {
        return query::print_query(&font, query).map_err(Error);
    }

    let filter = TableFilter::from_args(&args)?;
    print_tables(&font, &filter);
    Ok(())
}

fn list_tables(font: &FontRef) {
    println!("Tag  Offset  Length  Checksum");
    println!("-------------------------------");

    let offset_pad = get_offset_width(font);

    for record in font.table_directory.table_records() {
        println!(
            "{0} 0x{1:02$X} {3:8} 0x{4:08X} ",
            record.tag(),
            record.offset().to_u32(),
            offset_pad,
            record.length(),
            record.checksum()
        );
    }
}

fn print_tables(font: &FontRef, filter: &TableFilter) {
    let mut printed = HashSet::new();
    for tag in font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.tag())
        .filter(|tag| filter.should_print(*tag))
    {
        printed.insert(tag);
        print_table(font, tag)
    }

    if let TableFilter::Include(to_print) = filter {
        for unprinted in to_print.difference(&printed) {
            println!("Table {unprinted} not found");
        }
    }
}

fn get_offset_width(font: &FontRef) -> usize {
    // pick how much padding we use for offsets based on the max offset in directory
    let max_off = font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.offset().to_u32())
        .max()
        .unwrap_or_default();
    hex_width(max_off)
}

/// Return the number of hex digits required to represent a given number.
fn hex_width(val: u32) -> usize {
    match val {
        0..=0xffff => 4usize,
        0x10000..=0xffff_ff => 6,
        0x1000000.. => 8,
    }
}

/// Given a font and a tag, return the appropriate table as a [`dyn SomeTable`][SomeTable].
fn get_some_table<'a>(
    font: &FontRef<'a>,
    tag: Tag,
) -> Result<Box<dyn SomeTable<'a> + 'a>, ReadError> {
    match tag {
        read_fonts::tables::gpos::TAG => font.gpos().map(|x| Box::new(x) as _),
        read_fonts::tables::gsub::TAG => font.gsub().map(|x| Box::new(x) as _),
        read_fonts::tables::cmap::TAG => font.cmap().map(|x| Box::new(x) as _),
        read_fonts::tables::gdef::TAG => font.gdef().map(|x| Box::new(x) as _),
        read_fonts::tables::glyf::TAG => font.glyf().map(|x| Box::new(x) as _),
        read_fonts::tables::head::TAG => font.head().map(|x| Box::new(x) as _),
        read_fonts::tables::hhea::TAG => font.hhea().map(|x| Box::new(x) as _),
        read_fonts::tables::hmtx::TAG => font.hmtx().map(|x| Box::new(x) as _),
        read_fonts::tables::loca::TAG => font.loca(None).map(|x| Box::new(x) as _),
        read_fonts::tables::maxp::TAG => font.maxp().map(|x| Box::new(x) as _),
        read_fonts::tables::name::TAG => font.name().map(|x| Box::new(x) as _),
        read_fonts::tables::post::TAG => font.post().map(|x| Box::new(x) as _),
        read_fonts::tables::colr::TAG => font.colr().map(|x| Box::new(x) as _),
        read_fonts::tables::stat::TAG => font.stat().map(|x| Box::new(x) as _),
        read_fonts::tables::vhea::TAG => font.vhea().map(|x| Box::new(x) as _),
        read_fonts::tables::vmtx::TAG => font.vmtx().map(|x| Box::new(x) as _),
        _ => Err(ReadError::TableIsMissing(tag)),
    }
}

fn print_table(font: &FontRef, tag: Tag) {
    match get_some_table(font, tag) {
        Ok(table) => fancy_print_table(&table).unwrap(),
        Err(err) => println!("{tag}: Error '{err}'"),
    }
}

enum TableFilter {
    All,
    Include(HashSet<Tag>),
    Exclude(HashSet<Tag>),
}

impl TableFilter {
    fn from_args(args: &flags::Args) -> Result<Self, Error> {
        if args.tables.is_some() && args.exclude.is_some() {
            return Err(Error::new("pass only one of --tables and --exclude"));
        }
        if let Some(tags) = &args.tables {
            make_tag_set(tags).map(TableFilter::Include)
        } else if let Some(tags) = &args.exclude {
            make_tag_set(tags).map(TableFilter::Exclude)
        } else {
            Ok(TableFilter::All)
        }
    }

    fn should_print(&self, tag: Tag) -> bool {
        match self {
            TableFilter::All => true,
            TableFilter::Include(tags) => tags.contains(&tag),
            TableFilter::Exclude(tags) => !tags.contains(&tag),
        }
    }
}

fn make_tag_set(inp: &str) -> Result<HashSet<Tag>, Error> {
    inp.split(' ')
        .map(|raw| match Tag::from_str(raw) {
            Ok(tag) => Ok(tag),
            Err(e) => Err(Error(format!(
                "Invalid tag '{}': {e}",
                raw.escape_default()
            ))),
        })
        .collect()
}

#[derive(Debug, Clone)]
struct Error(String);

impl Error {
    fn new(t: impl std::fmt::Display) -> Self {
        Self(t.to_string())
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

impl std::error::Error for Error {}

fn fancy_print_table<'a>(table: &(dyn SomeTable<'a> + 'a)) -> std::io::Result<()> {
    let stdout = std::io::stdout();
    let mut locked = stdout.lock();
    let mut formatter = PrettyPrinter::new(&mut locked);
    formatter.print_root_table(table)
}

mod flags {
    use super::Query;
    use std::path::PathBuf;

    xflags::xflags! {
        /// Generate font table representations
        cmd args
            required input: PathBuf
            {
                optional -i, --index index: u32
                optional -l, --list
                optional -q, --query query: Query
                optional -t, --tables include: String
                optional -x, --exclude exclude: String
            }

    }
}
<|endoftext|>


<commit_before>#![feature(test)]

#[macro_use]
extern crate frunk;
#[macro_use]
extern crate frunk_core;
extern crate test;

use frunk::*;
use test::Bencher;

#[derive(LabelledGeneric)]
struct NewUser<'a> {
    first_name: &'a str,
    last_name: &'a str,
    age: usize
}

#[derive(LabelledGeneric)]
struct SavedUser<'a> {
    first_name: &'a str,
    last_name: &'a str,
    age: usize
}

#[bench]
fn labelled_conversion(b: &mut Bencher) {
    b.iter(|| {
        let n_u = NewUser {
            first_name: "Joe",
            last_name: "Schmoe",
            age: 30
        };
        <SavedUser as LabelledGeneric>::sculpted_convert_from(n_u)
    })
}

#[bench]
fn name(b: &mut Bencher) {
    let field = field!((f,i,r,s,t,__,n,a,m,e), 30);
    b.iter(|| {
        field.name
    })
}<commit_msg>Add comparison of labelled::convert_from and labelled::sculpted_convert_from<commit_after>#![feature(test)]

#[macro_use]
extern crate frunk;
#[macro_use]
extern crate frunk_core;
extern crate test;

use frunk::*;
use test::Bencher;

#[derive(LabelledGeneric)]
struct NewUser<'a> {
    first_name: &'a str,
    last_name: &'a str,
    age: usize
}

#[derive(LabelledGeneric)]
struct SavedUser<'a> {
    first_name: &'a str,
    last_name: &'a str,
    age: usize
}
#[derive(LabelledGeneric)]
struct JumbledUser<'a> {
    age: usize,
    last_name: &'a str,
    first_name: &'a str,
}

#[bench]
fn labelled_conversion(b: &mut Bencher) {
    b.iter(|| {
        let n_u = NewUser {
            first_name: "Joe",
            last_name: "Schmoe",
            age: 30
        };
        <SavedUser as LabelledGeneric>::convert_from(n_u)
    })
}
#[bench]
fn sculpted_conversion(b: &mut Bencher) {
    b.iter(|| {
        let n_u = NewUser {
            first_name: "Joe",
            last_name: "Schmoe",
            age: 30
        };
        <JumbledUser as LabelledGeneric>::sculpted_convert_from(n_u)
    })
}

#[bench]
fn name(b: &mut Bencher) {
    let field = field!((f,i,r,s,t,__,n,a,m,e), "Joe");
    b.iter(|| {
        field.name
    })
}<|endoftext|>


<commit_before>extern crate getopts;
use std::os;
use std::io;
use std::collections::HashMap;

use getopts::getopts;
use getopts::optflag;
use getopts::usage;

fn main() {
    let args: Vec<String> = os::args()
        .iter()
        .map(|x| x.to_string())
        .collect();

    let opts = [
        optflag("h", "help", "Show help.")
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_str()) }
    };

    if matches.opt_present("h") {
        println!("{}", usage("Produce a sorted-by-frequency list of lines from input.", opts));
        return;
    }

    let mut lines: HashMap<String,int> = HashMap::new();

    for line in io::stdin().lines() {
        lines.insert_or_update_with(line.unwrap(), 1, |_k, v| *v = *v + 1);
    }

    let mut sorted_lines: Vec<(int, String)> = Vec::new();

    for (line, count) in lines.iter() {
        sorted_lines.push((*count, line.clone()));
    }

    sorted_lines.sort_by(|a, b| b.cmp(a));

    for &(ref count, ref line) in sorted_lines.iter() {
        print!("{} {}", count, line);
    }
}
<commit_msg>to_str -> to_string (changed in rust)<commit_after>extern crate getopts;
use std::os;
use std::io;
use std::collections::HashMap;

use getopts::getopts;
use getopts::optflag;
use getopts::usage;

fn main() {
    let args: Vec<String> = os::args()
        .iter()
        .map(|x| x.to_string())
        .collect();

    let opts = [
        optflag("h", "help", "Show help.")
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_string()) }
    };

    if matches.opt_present("h") {
        println!("{}", usage("Produce a sorted-by-frequency list of lines from input.", opts));
        return;
    }

    let mut lines: HashMap<String,int> = HashMap::new();

    for line in io::stdin().lines() {
        lines.insert_or_update_with(line.unwrap(), 1, |_k, v| *v = *v + 1);
    }

    let mut sorted_lines: Vec<(int, String)> = Vec::new();

    for (line, count) in lines.iter() {
        sorted_lines.push((*count, line.clone()));
    }

    sorted_lines.sort_by(|a, b| b.cmp(a));

    for &(ref count, ref line) in sorted_lines.iter() {
        print!("{} {}", count, line);
    }
}
<|endoftext|>


<commit_before>use webcore::value::{Reference, Value};
use webcore::try_from::{TryInto, TryFrom};
use webapi::event_target::{IEventTarget, EventTarget};
use webapi::node::{INode, Node, CloneKind};
use webapi::element::Element;
use webapi::html_element::HtmlElement;
use webapi::document_fragment::DocumentFragment;
use webapi::text_node::TextNode;
use webapi::location::Location;
use webapi::parent_node::IParentNode;
use webapi::non_element_parent_node::INonElementParentNode;
use webapi::dom_exception::{InvalidCharacterError, NamespaceError, NotSupportedError};

/// The `Document` interface represents any web page loaded in the browser and
/// serves as an entry point into the web page's content, which is the DOM tree.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document)
// https://dom.spec.whatwg.org/#document
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Document")]
#[reference(subclass_of(EventTarget, Node))]
pub struct Document( Reference );

error_enum_boilerplate! {
    CreateElementNsError,
    InvalidCharacterError,
    NamespaceError
}

impl IEventTarget for Document {}
impl IParentNode for Document {}
impl INode for Document {}

impl INonElementParentNode for Document {}

/// A global instance of [Document](struct.Document.html).
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document)
pub fn document() -> Document {
    unsafe { js!( return document; ).into_reference_unchecked() }.unwrap()
}

impl Document {
    /// In an HTML document, the Document.createDocumentFragment() method creates a
    /// new empty DocumentFragment.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createdocumentfragment
    pub fn create_document_fragment( &self ) -> DocumentFragment {
        unsafe {
            js!( return @{self}.createDocumentFragment(); ).into_reference_unchecked().unwrap()
        }
    }

    /// In an HTML document, the Document.createElement() method creates the HTML
    /// element specified by `tag`, or an HTMLUnknownElement if `tag` isn't
    /// recognized. In other documents, it creates an element with a null namespace URI.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createelement
    pub fn create_element( &self, tag: &str ) -> Result< Element, InvalidCharacterError > {
        js_try!( return @{self}.createElement( @{tag} ); ).unwrap()
    }

    /// Creates an element with the specified namespace URI and qualified name.
    /// To create an element without specifying a namespace URI, use the `createElement` method.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createelementns
    pub fn create_element_ns( &self, namespace_uri: &str, tag: &str ) -> Result< Element, CreateElementNsError > {
        js_try!(
            return @{self}.createElementNS( @{namespace_uri}, @{tag} );
        ).unwrap()
    }

    /// Creates a new text node.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createtextnode
    pub fn create_text_node( &self, text: &str ) -> TextNode {
        unsafe {
            js!( return @{self}.createTextNode( @{text} ); ).into_reference_unchecked().unwrap()
        }
    }

    /// Returns a [Location](struct.Location.html) object which contains
    /// information about the URL of the document and provides methods
    /// for changing that URL and loading another URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/location)
    // https://html.spec.whatwg.org/#the-document-object:dom-document-location
    pub fn location( &self ) -> Option< Location > {
        unsafe {
            js!(
                return @{self}.location;
            ).into_reference_unchecked()
        }
    }

    /// Returns the `<body>` or `<frameset>` node of the current document, or null if no such element exists.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/body)
    // https://html.spec.whatwg.org/#the-document-object:dom-document-body
    pub fn body( &self ) -> Option< HtmlElement > {
        unsafe {
            js!(
                return @{self}.body;
            ).into_reference_unchecked()
        }
    }

    /// Returns the `<head>` element of the current document. If there are more than one `<head>`
    /// elements, the first one is returned.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/head)
    // https://html.spec.whatwg.org/#the-document-object:dom-document-head
    pub fn head( &self ) -> Option< HtmlElement > {
        unsafe {
            js!(
                return @{self}.head;
            ).into_reference_unchecked()
        }
    }

    /// Gets the title of the document.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/title)
    // https://html.spec.whatwg.org/#the-document-object:document.title
    pub fn title( &self ) -> String {
        unsafe {
            js!(
                return @{self}.title;
            ).try_into().unwrap()
        }
    }

    /// Sets the title of the document.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/title)
    // https://html.spec.whatwg.org/#the-document-object:document.title
    pub fn set_title( &self, title: &str ) {
        unsafe {
            js!( @(no_return) @{self}.title = @{title}; );
        }
    }

    /// Returns the Element that is the root element of the document (for example, the `<html>`
    /// element for HTML documents).
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/documentElement)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-documentelement
    pub fn document_element( &self ) -> Option< Element > {
        unsafe {
            js!(
                return @{self}.documentElement;
            ).try_into().unwrap()
        }
    }

    /// Returns the Element that the pointer is locked to, if it is locked to any
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/pointerLockElement)
    // https://w3c.github.io/pointerlock/#dom-documentorshadowroot-pointerlockelement
    pub fn pointer_lock_element( &self ) -> Option< Element > {
        let value = js!(
            return @{self}.pointerLockElement;
        );
        match value {
            Value::Null | Value::Undefined => None,
            Value::Reference(reference) => Some(reference.try_into().unwrap()),
            _ => unreachable!()
        }
    }

    /// Exit the pointer lock on the current element
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/exitPointerLock)
    // https://w3c.github.io/pointerlock/#dom-document-exitpointerlock
    pub fn exit_pointer_lock( &self ) {
        js!( @(no_return)
            @{self}.exitPointerLock();
        );
    }

    /// Import node from another document
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/importNode)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-importnode
    pub fn import_node<N: INode>( &self, n: &N, kind: CloneKind ) -> Result<Node, NotSupportedError> {
        let deep = match kind {
            CloneKind::Deep => true,
            CloneKind::Shallow => false,
        };

        js_try!(
            return @{self}.importNode( @{n.as_ref()}, @{deep} );
        ).unwrap()
    }
}

#[cfg(all(test, feature = "web_test"))]
mod web_tests {
    use super::*;
    use webapi::node::{Node, INode, CloneKind};
    use webapi::html_elements::TemplateElement;
    use webapi::html_element::HtmlElement;

    #[test]
    fn test_create_element_invalid_character() {
        match document().create_element("-invalid tag") {
            Err(InvalidCharacterError{..}) => (),
            v => panic!("expected InvalidCharacterError, got {:?}", v),
        }
    }

    #[test]
    fn test_create_element_ns_invalid_character() {
        match document().create_element_ns("", "-invalid tag") {
            Err(CreateElementNsError::InvalidCharacterError(_)) => (),
            v => panic!("expected InvalidCharacterError, got {:?}", v),
        }
    }

    #[test]
    fn test_create_element_ns_namespace_error() {
        match document().create_element_ns("", "illegal_prefix:svg") {
            Err(CreateElementNsError::NamespaceError(_)) => (),
            v => panic!("expected NamespaceError, got {:?}", v),
        }
    }

    #[test]
    fn test_import_node() {
        let document = document();
        let tpl: TemplateElement = Node::from_html("<template>aaabbbcccddd</template>")
            .unwrap()
            .try_into()
            .unwrap();

        let n = document.import_node(&tpl.content(), CloneKind::Deep).unwrap();
        let child_nodes = n.child_nodes();
        assert_eq!(child_nodes.len(), 1);

        let span_element: HtmlElement = child_nodes.iter().next().unwrap().try_into().unwrap();

        assert_eq!(span_element.node_name(), "SPAN");
        assert_eq!(js!( return @{span_element}.innerHTML; ), "aaabbbcccddd");
    }
}
<commit_msg>Get rid of unnecessary `unsafe`s<commit_after>use webcore::value::{Reference, Value};
use webcore::try_from::{TryInto, TryFrom};
use webapi::event_target::{IEventTarget, EventTarget};
use webapi::node::{INode, Node, CloneKind};
use webapi::element::Element;
use webapi::html_element::HtmlElement;
use webapi::document_fragment::DocumentFragment;
use webapi::text_node::TextNode;
use webapi::location::Location;
use webapi::parent_node::IParentNode;
use webapi::non_element_parent_node::INonElementParentNode;
use webapi::dom_exception::{InvalidCharacterError, NamespaceError, NotSupportedError};

/// The `Document` interface represents any web page loaded in the browser and
/// serves as an entry point into the web page's content, which is the DOM tree.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document)
// https://dom.spec.whatwg.org/#document
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Document")]
#[reference(subclass_of(EventTarget, Node))]
pub struct Document( Reference );

error_enum_boilerplate! {
    CreateElementNsError,
    InvalidCharacterError,
    NamespaceError
}

impl IEventTarget for Document {}
impl IParentNode for Document {}
impl INode for Document {}

impl INonElementParentNode for Document {}

/// A global instance of [Document](struct.Document.html).
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document)
pub fn document() -> Document {
    unsafe { js!( return document; ).into_reference_unchecked() }.unwrap()
}

impl Document {
    /// In an HTML document, the Document.createDocumentFragment() method creates a
    /// new empty DocumentFragment.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createdocumentfragment
    pub fn create_document_fragment( &self ) -> DocumentFragment {
        unsafe {
            js!( return @{self}.createDocumentFragment(); ).into_reference_unchecked().unwrap()
        }
    }

    /// In an HTML document, the Document.createElement() method creates the HTML
    /// element specified by `tag`, or an HTMLUnknownElement if `tag` isn't
    /// recognized. In other documents, it creates an element with a null namespace URI.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createelement
    pub fn create_element( &self, tag: &str ) -> Result< Element, InvalidCharacterError > {
        js_try!( return @{self}.createElement( @{tag} ); ).unwrap()
    }

    /// Creates an element with the specified namespace URI and qualified name.
    /// To create an element without specifying a namespace URI, use the `createElement` method.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createelementns
    pub fn create_element_ns( &self, namespace_uri: &str, tag: &str ) -> Result< Element, CreateElementNsError > {
        js_try!(
            return @{self}.createElementNS( @{namespace_uri}, @{tag} );
        ).unwrap()
    }

    /// Creates a new text node.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createtextnode
    pub fn create_text_node( &self, text: &str ) -> TextNode {
        unsafe {
            js!( return @{self}.createTextNode( @{text} ); ).into_reference_unchecked().unwrap()
        }
    }

    /// Returns a [Location](struct.Location.html) object which contains
    /// information about the URL of the document and provides methods
    /// for changing that URL and loading another URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/location)
    // https://html.spec.whatwg.org/#the-document-object:dom-document-location
    pub fn location( &self ) -> Option< Location > {
        unsafe {
            js!(
                return @{self}.location;
            ).into_reference_unchecked()
        }
    }

    /// Returns the `<body>` or `<frameset>` node of the current document, or null if no such element exists.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/body)
    // https://html.spec.whatwg.org/#the-document-object:dom-document-body
    pub fn body( &self ) -> Option< HtmlElement > {
        unsafe {
            js!(
                return @{self}.body;
            ).into_reference_unchecked()
        }
    }

    /// Returns the `<head>` element of the current document. If there are more than one `<head>`
    /// elements, the first one is returned.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/head)
    // https://html.spec.whatwg.org/#the-document-object:dom-document-head
    pub fn head( &self ) -> Option< HtmlElement > {
        unsafe {
            js!(
                return @{self}.head;
            ).into_reference_unchecked()
        }
    }

    /// Gets the title of the document.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/title)
    // https://html.spec.whatwg.org/#the-document-object:document.title
    pub fn title( &self ) -> String {
        js!(
            return @{self}.title;
        ).try_into().unwrap()
    }

    /// Sets the title of the document.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/title)
    // https://html.spec.whatwg.org/#the-document-object:document.title
    pub fn set_title( &self, title: &str ) {
        js!( @(no_return) @{self}.title = @{title}; );
    }

    /// Returns the Element that is the root element of the document (for example, the `<html>`
    /// element for HTML documents).
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/documentElement)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-documentelement
    pub fn document_element( &self ) -> Option< Element > {
        js!(
            return @{self}.documentElement;
        ).try_into().unwrap()
    }

    /// Returns the Element that the pointer is locked to, if it is locked to any
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/pointerLockElement)
    // https://w3c.github.io/pointerlock/#dom-documentorshadowroot-pointerlockelement
    pub fn pointer_lock_element( &self ) -> Option< Element > {
        let value = js!(
            return @{self}.pointerLockElement;
        );
        match value {
            Value::Null | Value::Undefined => None,
            Value::Reference(reference) => Some(reference.try_into().unwrap()),
            _ => unreachable!()
        }
    }

    /// Exit the pointer lock on the current element
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/exitPointerLock)
    // https://w3c.github.io/pointerlock/#dom-document-exitpointerlock
    pub fn exit_pointer_lock( &self ) {
        js!( @(no_return)
            @{self}.exitPointerLock();
        );
    }

    /// Import node from another document
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/importNode)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-importnode
    pub fn import_node<N: INode>( &self, n: &N, kind: CloneKind ) -> Result<Node, NotSupportedError> {
        let deep = match kind {
            CloneKind::Deep => true,
            CloneKind::Shallow => false,
        };

        js_try!(
            return @{self}.importNode( @{n.as_ref()}, @{deep} );
        ).unwrap()
    }
}

#[cfg(all(test, feature = "web_test"))]
mod web_tests {
    use super::*;
    use webapi::node::{Node, INode, CloneKind};
    use webapi::html_elements::TemplateElement;
    use webapi::html_element::HtmlElement;

    #[test]
    fn test_create_element_invalid_character() {
        match document().create_element("-invalid tag") {
            Err(InvalidCharacterError{..}) => (),
            v => panic!("expected InvalidCharacterError, got {:?}", v),
        }
    }

    #[test]
    fn test_create_element_ns_invalid_character() {
        match document().create_element_ns("", "-invalid tag") {
            Err(CreateElementNsError::InvalidCharacterError(_)) => (),
            v => panic!("expected InvalidCharacterError, got {:?}", v),
        }
    }

    #[test]
    fn test_create_element_ns_namespace_error() {
        match document().create_element_ns("", "illegal_prefix:svg") {
            Err(CreateElementNsError::NamespaceError(_)) => (),
            v => panic!("expected NamespaceError, got {:?}", v),
        }
    }

    #[test]
    fn test_import_node() {
        let document = document();
        let tpl: TemplateElement = Node::from_html("<template>aaabbbcccddd</template>")
            .unwrap()
            .try_into()
            .unwrap();

        let n = document.import_node(&tpl.content(), CloneKind::Deep).unwrap();
        let child_nodes = n.child_nodes();
        assert_eq!(child_nodes.len(), 1);

        let span_element: HtmlElement = child_nodes.iter().next().unwrap().try_into().unwrap();

        assert_eq!(span_element.node_name(), "SPAN");
        assert_eq!(js!( return @{span_element}.innerHTML; ), "aaabbbcccddd");
    }
}
<|endoftext|>


<commit_before>//! Http client request
use std::io;

use actix_net::connector::ConnectorError;
use http::header::HeaderValue;
use http::StatusCode;

use error::ParseError;
use http::Error as HttpError;
use ws::ProtocolError;

/// Websocket client error
#[derive(Fail, Debug)]
pub enum ClientError {
    /// Invalid url
    #[fail(display = "Invalid url")]
    InvalidUrl,
    /// Invalid response status
    #[fail(display = "Invalid response status")]
    InvalidResponseStatus(StatusCode),
    /// Invalid upgrade header
    #[fail(display = "Invalid upgrade header")]
    InvalidUpgradeHeader,
    /// Invalid connection header
    #[fail(display = "Invalid connection header")]
    InvalidConnectionHeader(HeaderValue),
    /// Missing CONNECTION header
    #[fail(display = "Missing CONNECTION header")]
    MissingConnectionHeader,
    /// Missing SEC-WEBSOCKET-ACCEPT header
    #[fail(display = "Missing SEC-WEBSOCKET-ACCEPT header")]
    MissingWebSocketAcceptHeader,
    /// Invalid challenge response
    #[fail(display = "Invalid challenge response")]
    InvalidChallengeResponse(String, HeaderValue),
    /// Http parsing error
    #[fail(display = "Http parsing error")]
    Http(HttpError),
    /// Response parsing error
    #[fail(display = "Response parsing error: {}", _0)]
    ParseError(ParseError),
    /// Protocol error
    #[fail(display = "{}", _0)]
    Protocol(#[cause] ProtocolError),
    /// Connect error
    #[fail(display = "{:?}", _0)]
    Connect(ConnectorError),
    /// IO Error
    #[fail(display = "{}", _0)]
    Io(io::Error),
    /// "Disconnected"
    #[fail(display = "Disconnected")]
    Disconnected,
}

impl From<HttpError> for ClientError {
    fn from(err: HttpError) -> ClientError {
        ClientError::Http(err)
    }
}

impl From<ConnectorError> for ClientError {
    fn from(err: ConnectorError) -> ClientError {
        ClientError::Connect(err)
    }
}

impl From<ProtocolError> for ClientError {
    fn from(err: ProtocolError) -> ClientError {
        ClientError::Protocol(err)
    }
}

impl From<io::Error> for ClientError {
    fn from(err: io::Error) -> ClientError {
        ClientError::Io(err)
    }
}

impl From<ParseError> for ClientError {
    fn from(err: ParseError) -> ClientError {
        ClientError::ParseError(err)
    }
}
<commit_msg>add cause for nested errors<commit_after>//! Http client request
use std::io;

use actix_net::connector::ConnectorError;
use http::header::HeaderValue;
use http::StatusCode;

use error::ParseError;
use http::Error as HttpError;
use ws::ProtocolError;

/// Websocket client error
#[derive(Fail, Debug)]
pub enum ClientError {
    /// Invalid url
    #[fail(display = "Invalid url")]
    InvalidUrl,
    /// Invalid response status
    #[fail(display = "Invalid response status")]
    InvalidResponseStatus(StatusCode),
    /// Invalid upgrade header
    #[fail(display = "Invalid upgrade header")]
    InvalidUpgradeHeader,
    /// Invalid connection header
    #[fail(display = "Invalid connection header")]
    InvalidConnectionHeader(HeaderValue),
    /// Missing CONNECTION header
    #[fail(display = "Missing CONNECTION header")]
    MissingConnectionHeader,
    /// Missing SEC-WEBSOCKET-ACCEPT header
    #[fail(display = "Missing SEC-WEBSOCKET-ACCEPT header")]
    MissingWebSocketAcceptHeader,
    /// Invalid challenge response
    #[fail(display = "Invalid challenge response")]
    InvalidChallengeResponse(String, HeaderValue),
    /// Http parsing error
    #[fail(display = "Http parsing error")]
    Http(#[cause] HttpError),
    /// Response parsing error
    #[fail(display = "Response parsing error: {}", _0)]
    ParseError(#[cause] ParseError),
    /// Protocol error
    #[fail(display = "{}", _0)]
    Protocol(#[cause] ProtocolError),
    /// Connect error
    #[fail(display = "Connector error: {:?}", _0)]
    Connect(ConnectorError),
    /// IO Error
    #[fail(display = "{}", _0)]
    Io(#[cause] io::Error),
    /// "Disconnected"
    #[fail(display = "Disconnected")]
    Disconnected,
}

impl From<HttpError> for ClientError {
    fn from(err: HttpError) -> ClientError {
        ClientError::Http(err)
    }
}

impl From<ConnectorError> for ClientError {
    fn from(err: ConnectorError) -> ClientError {
        ClientError::Connect(err)
    }
}

impl From<ProtocolError> for ClientError {
    fn from(err: ProtocolError) -> ClientError {
        ClientError::Protocol(err)
    }
}

impl From<io::Error> for ClientError {
    fn from(err: io::Error) -> ClientError {
        ClientError::Io(err)
    }
}

impl From<ParseError> for ClientError {
    fn from(err: ParseError) -> ClientError {
        ClientError::ParseError(err)
    }
}
<|endoftext|>


<commit_before>pub use askama;
pub use tide;

use askama::*;
use tide::{http::Mime, Body, Response};

pub fn try_into_body<T: Template>(t: &T, ext: &str) -> Result<Body> {
    let string = t.render()?;
    let mut body = Body::from_string(string);

    if let Some(mime) = Mime::from_extension(ext) {
        body.set_mime(mime);
    }

    Ok(body)
}

pub fn into_response<T: Template>(t: &T, ext: &str) -> Response {
    match try_into_body(t, ext) {
        Ok(body) => {
            let mut response = Response::new(200);
            response.set_body(body);
            response
        }

        Err(e) => {
            let mut response = Response::new(500);
            response.set_body(e.to_string());
            response
        }
    }
}
<commit_msg>tide: use set_error for correct error handling<commit_after>pub use askama;
pub use tide;

use askama::*;
use tide::{http::Mime, Body, Response};

pub fn try_into_body<T: Template>(t: &T, ext: &str) -> Result<Body> {
    let string = t.render()?;
    let mut body = Body::from_string(string);

    if let Some(mime) = Mime::from_extension(ext) {
        body.set_mime(mime);
    }

    Ok(body)
}

pub fn into_response<T: Template>(t: &T, ext: &str) -> Response {
    match try_into_body(t, ext) {
        Ok(body) => {
            let mut response = Response::new(200);
            response.set_body(body);
            response
        }

        Err(error) => {
            let mut response = Response::new(500);
            response.set_error(error);
            response
        }
    }
}
<|endoftext|>


<commit_before>//! Module containing the types for User Defined Attributes (UDA)

/// UDA Name
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct UDAName(String);

impl<'a> From<&'a str> for UDAName {

    fn from(s: &str) -> UDAName {
        UDAName(String::from(s))
    }

}

impl From<String> for UDAName {

    fn from(s: String) -> UDAName {
        UDAName(s)
    }

}

/// UDA Value
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct UDAValue(String);

impl<'a> From<&'a str> for UDAValue {

    fn from(s: &str) -> UDAValue {
        UDAValue(String::from(s))
    }

}

impl From<String> for UDAValue {

    fn from(s: String) -> UDAValue {
        UDAValue(s)
    }

}

<commit_msg>Impl Deref,DerefMut,Default for UDA<commit_after>//! Module containing the types for User Defined Attributes (UDA)

use std::ops::{Deref, DerefMut};
use std::default::Default;
use std::collections::BTreeMap;

/// UDA Name
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct UDAName(String);

impl<'a> From<&'a str> for UDAName {

    fn from(s: &str) -> UDAName {
        UDAName(String::from(s))
    }

}

impl From<String> for UDAName {

    fn from(s: String) -> UDAName {
        UDAName(s)
    }

}

/// UDA Value
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct UDAValue(String);

impl<'a> From<&'a str> for UDAValue {

    fn from(s: &str) -> UDAValue {
        UDAValue(String::from(s))
    }

}

impl From<String> for UDAValue {

    fn from(s: String) -> UDAValue {
        UDAValue(s)
    }

}

/// Wrapper type for BTreeMap<UDAName, UDAValue> so serde does not automatically implement the
/// Deserialize trait on it.
#[derive(Clone, Debug)]
pub struct UDA(BTreeMap<UDAName, UDAValue>);

impl Deref for UDA {
    type Target = BTreeMap<UDAName, UDAValue>;

    fn deref(&self) -> &BTreeMap<UDAName, UDAValue> {
        &self.0
    }

}

impl DerefMut for UDA {

    fn deref_mut(&mut self) -> &mut BTreeMap<UDAName, UDAValue> {
        &mut self.0
    }

}

impl Default for UDA {

    fn default() -> UDA {
        UDA(BTreeMap::new())
    }

}

<|endoftext|>


<commit_before>
use bwapi_sys as sys;
use std::ffi::CString;
use iterator::{BwIterator, FromRaw};

use unit::Unit;
use player::Player;
use region::Region;

use position::Position;

use std::os::raw::c_void as void;
pub trait EventHandler {
    fn on_start(&mut self);
    fn on_end(&mut self, is_winner: bool);
    fn on_frame(&mut self);
    fn on_send_text(&mut self, text: &str);
    fn on_receive_text(&mut self, player: &mut Player, text: &str);
    fn on_player_left(&mut self, player: &mut Player);
    fn on_nuke_detect(&mut self, target: Position);
    fn on_unit_discover(&mut self, unit: &mut Unit);
    fn on_unit_evade(&mut self, unit: &mut Unit);
    fn on_unit_show(&mut self, unit: &mut Unit);
    fn on_unit_hide(&mut self, unit: &mut Unit);
    fn on_unit_create(&mut self, unit: &mut Unit);
    fn on_unit_destroy(&mut self, unit: &mut Unit);
    fn on_unit_morph(&mut self, unit: &mut Unit);
    fn on_unit_renegade(&mut self, unit: &mut Unit);
    fn on_save_game(&mut self, game_name: &str);
    fn on_unit_complete(&mut self, unit: &mut Unit);
}

pub struct Game(*mut sys::Game);

impl FromRaw for Game {
    unsafe fn from_raw(raw: *mut void) -> Game {
        assert!(!raw.is_null());
        Game(raw as *mut sys::Game)
    }
}

pub enum CoordinateType {
    None = 0,
    Screen = 1,
    Map = 2,
    Mouse = 3
}

pub enum CheatFlag {
    CompleteMapInfo = 0,
    UserInput = 1,
}

pub enum CommandOptLevel {
    None = 0,
    Some = 1,
    More = 2,
    Extensive = 3,
    Aggressive = 4
}

impl Game {
    pub fn enable_flag(&self, flag: CheatFlag) {
        unsafe {
            sys::Game_enableFlag(self.0, flag as i32);
        }
    }

    pub fn send_text(&self, text: &str) {
        unsafe {
            let data = CString::new(text).unwrap();
            sys::Game_sendText(self.0, data.as_ptr());
        }
    }

    pub fn frame_count(&self) -> i32 {
        unsafe {
            sys::Game_getFrameCount(self.0)
        }
    }

    pub fn get_apm(&self, include_selects: bool) -> i32 {
        unsafe {
            sys::Game_getAPM(self.0, include_selects)
        }
    }

    pub fn set_command_optimization_level(&self, level: CommandOptLevel) {
        unsafe {
            sys::Game_setCommandOptimizationLevel(self.0, level as i32)
        }
    }

    pub fn draw_text(&self, ctype: CoordinateType, coords: (i32, i32), text: &str) {
        unsafe {
            let data  = CString::new(text).unwrap();
            let ctype = sys::CoordinateType { id: ctype as i32 };
            sys::Game_drawText(self.0, ctype, coords.0, coords.1, data.as_ptr());
        }
    }

    pub fn draw_line(&self, ctype: CoordinateType, first: (i32, i32), second: (i32, i32), color: sys::Color) {
        unsafe {
            let ctype = sys::CoordinateType { id: ctype as i32 };
            sys::Game_drawLine(self.0, ctype, first.0, first.1, second.0, second.1, color);
        }
    }

    pub fn self_player(&self) -> Player {
        unsafe {
            Player::from_raw(sys::Game_self(self.0) as *mut void)
        }
    }

    pub fn minerals(&self) -> Box<Iterator<Item=Unit>> {
        unsafe {
            let iter = sys::Game_getMinerals(self.0) as *mut sys::Iterator;
            Box::new(BwIterator::from(iter))
        }
    }

    pub fn regions(&self) -> Box<Iterator<Item=Region>> {
        unsafe {
            let iter = sys::Game_getAllRegions(self.0) as *mut sys::Iterator;
            Box::new(BwIterator::from(iter))
        }
    }
}
<commit_msg>Add Game::average_fps<commit_after>
use bwapi_sys as sys;
use std::ffi::CString;
use iterator::{BwIterator, FromRaw};

use unit::Unit;
use player::Player;
use region::Region;

use position::Position;

use std::os::raw::c_void as void;
pub trait EventHandler {
    fn on_start(&mut self);
    fn on_end(&mut self, is_winner: bool);
    fn on_frame(&mut self);
    fn on_send_text(&mut self, text: &str);
    fn on_receive_text(&mut self, player: &mut Player, text: &str);
    fn on_player_left(&mut self, player: &mut Player);
    fn on_nuke_detect(&mut self, target: Position);
    fn on_unit_discover(&mut self, unit: &mut Unit);
    fn on_unit_evade(&mut self, unit: &mut Unit);
    fn on_unit_show(&mut self, unit: &mut Unit);
    fn on_unit_hide(&mut self, unit: &mut Unit);
    fn on_unit_create(&mut self, unit: &mut Unit);
    fn on_unit_destroy(&mut self, unit: &mut Unit);
    fn on_unit_morph(&mut self, unit: &mut Unit);
    fn on_unit_renegade(&mut self, unit: &mut Unit);
    fn on_save_game(&mut self, game_name: &str);
    fn on_unit_complete(&mut self, unit: &mut Unit);
}

pub struct Game(*mut sys::Game);

impl FromRaw for Game {
    unsafe fn from_raw(raw: *mut void) -> Game {
        assert!(!raw.is_null());
        Game(raw as *mut sys::Game)
    }
}

pub enum CoordinateType {
    None = 0,
    Screen = 1,
    Map = 2,
    Mouse = 3
}

pub enum CheatFlag {
    CompleteMapInfo = 0,
    UserInput = 1,
}

pub enum CommandOptLevel {
    None = 0,
    Some = 1,
    More = 2,
    Extensive = 3,
    Aggressive = 4
}

impl Game {
    pub fn enable_flag(&self, flag: CheatFlag) {
        unsafe {
            sys::Game_enableFlag(self.0, flag as i32);
        }
    }

    pub fn send_text(&self, text: &str) {
        unsafe {
            let data = CString::new(text).unwrap();
            sys::Game_sendText(self.0, data.as_ptr());
        }
    }

    pub fn frame_count(&self) -> i32 {
        unsafe {
            sys::Game_getFrameCount(self.0)
        }
    }

    pub fn average_fps(&self) -> f64 {
        unsafe {
            sys::Game_getAverageFPS(self.0)
        }
    }

    pub fn get_apm(&self, include_selects: bool) -> i32 {
        unsafe {
            sys::Game_getAPM(self.0, include_selects)
        }
    }

    pub fn set_command_optimization_level(&self, level: CommandOptLevel) {
        unsafe {
            sys::Game_setCommandOptimizationLevel(self.0, level as i32)
        }
    }

    pub fn draw_text(&self, ctype: CoordinateType, coords: (i32, i32), text: &str) {
        unsafe {
            let data  = CString::new(text).unwrap();
            let ctype = sys::CoordinateType { id: ctype as i32 };
            sys::Game_drawText(self.0, ctype, coords.0, coords.1, data.as_ptr());
        }
    }

    pub fn draw_line(&self, ctype: CoordinateType, first: (i32, i32), second: (i32, i32), color: sys::Color) {
        unsafe {
            let ctype = sys::CoordinateType { id: ctype as i32 };
            sys::Game_drawLine(self.0, ctype, first.0, first.1, second.0, second.1, color);
        }
    }

    pub fn self_player(&self) -> Player {
        unsafe {
            Player::from_raw(sys::Game_self(self.0) as *mut void)
        }
    }

    pub fn minerals(&self) -> Box<Iterator<Item=Unit>> {
        unsafe {
            let iter = sys::Game_getMinerals(self.0) as *mut sys::Iterator;
            Box::new(BwIterator::from(iter))
        }
    }

    pub fn regions(&self) -> Box<Iterator<Item=Region>> {
        unsafe {
            let iter = sys::Game_getAllRegions(self.0) as *mut sys::Iterator;
            Box::new(BwIterator::from(iter))
        }
    }
}
<|endoftext|>


<commit_before>//! Game loop.

// Local crate.
use GameEvent;
use GameWindow = game_window::GameWindow;
use GameIteratorSettings;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// Implemented by game applications.
pub trait Game {
    /// Render graphics.
    fn render(&mut self, _args: &mut RenderArgs) {}

    /// Update the physical state of the game.
    fn update(&mut self, _args: &mut UpdateArgs) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(&mut self, _args: &KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: &KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: &MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: &MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: &MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: &MouseRelativeMoveArgs) {}

    /// Handles a game event.
    fn event(&mut self, event: &mut GameEvent) {
        match *event {
            Render(ref mut args) => self.render(args),
            Update(ref mut args) => self.update(args),
            KeyPress(ref args) => self.key_press(args),
            KeyRelease(ref args) => self.key_release(args),
            MousePress(ref args) => self.mouse_press(args),
            MouseRelease(ref args) => self.mouse_release(args),
            MouseMove(ref args) => self.mouse_move(args),
            MouseRelativeMove(ref args) => self.mouse_relative_move(args),
        }
    }

    /// Executes a game loop.
    fn run<W: GameWindow>(
        &mut self,
        game_window: &mut W,
        game_iter_settings: &GameIteratorSettings
    ) {
        let mut game_iter = GameIterator::new(
            game_window,
            game_iter_settings
        );

        self.load();

        loop {
            match game_iter.next() {
                None => break,
                Some(mut e) => self.event(&mut e)
            }
        }
    }
}

<commit_msg>Made `render` and `update` take immutable Args<commit_after>//! Game loop.

// Local crate.
use GameEvent;
use GameWindow = game_window::GameWindow;
use GameIteratorSettings;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// Implemented by game applications.
pub trait Game {
    /// Render graphics.
    fn render(&mut self, _args: &RenderArgs) {}

    /// Update the physical state of the game.
    fn update(&mut self, _args: &UpdateArgs) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(&mut self, _args: &KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: &KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: &MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: &MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: &MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: &MouseRelativeMoveArgs) {}

    /// Handles a game event.
    fn event(&mut self, event: &mut GameEvent) {
        match *event {
            Render(ref mut args) => self.render(args),
            Update(ref mut args) => self.update(args),
            KeyPress(ref args) => self.key_press(args),
            KeyRelease(ref args) => self.key_release(args),
            MousePress(ref args) => self.mouse_press(args),
            MouseRelease(ref args) => self.mouse_release(args),
            MouseMove(ref args) => self.mouse_move(args),
            MouseRelativeMove(ref args) => self.mouse_relative_move(args),
        }
    }

    /// Executes a game loop.
    fn run<W: GameWindow>(
        &mut self,
        game_window: &mut W,
        game_iter_settings: &GameIteratorSettings
    ) {
        let mut game_iter = GameIterator::new(
            game_window,
            game_iter_settings
        );

        self.load();

        loop {
            match game_iter.next() {
                None => break,
                Some(mut e) => self.event(&mut e)
            }
        }
    }
}

<|endoftext|>


<commit_before>use ::korome::*;
use ::obj::*;

use std::ops::Deref;

pub struct SpaceShooter<'a>{
    objs: ObjSystem<'a>,
    player: &'a Texture,
    sun   : &'a Texture,
    planet: &'a Texture,
    arrow : &'a Texture,
    laser : &'a Texture,
    oobb  : OutOfBoundsBehaviour,
    dbg_a : bool,
    deltas: Vec<f64>,
}

use std::ops::Drop;

impl<'a> Drop for SpaceShooter<'a>{
    fn drop(&mut self){
        use std::fs::File;
        use std::io::{Write, BufWriter};

        let file = File::create("deltas.log").unwrap();
        let mut writer = BufWriter::new(file);

        let (len, mut min, mut max, mut sum) = (self.deltas.len(), ::std::f64::MAX, 0f64, 0.);

        for n in self.deltas.drain(..){
            min = min.min(n);
            max = max.max(n);
            sum += n;

            writer.write_fmt(format_args!("{}s ~ {}fps\n", n, 1./n)).unwrap()
        }

        let avg = sum/len as f64;

        println!("Total  : {}s", sum);
        println!("Best   : {}s ~ {}fps", min, 1./min);
        println!("Worst  : {}s ~ {}fps", max, 1./max);
        println!("Average: {}s ~ {}fps", avg, 1./avg);
    }
}

impl<'a> SpaceShooter<'a>{
    pub fn new(planet: &'a Texture, player: &'a Texture, sun: &'a Texture, arrow: &'a Texture, laser: &'a Texture) -> Self{
        let mut objs = ObjSystem::new();
        objs.players.push(new_player(player));

        SpaceShooter{
            player: player,
            sun   : sun,
            objs  : objs,
            planet: planet,
            arrow : arrow,
            laser : laser,
            oobb  : Bounce,
            dbg_a : true,
            deltas: Vec::with_capacity(10_000),
        }
    }

    fn add_player(&mut self){
        self.objs.players.push(new_player(self.player))
    }

    fn add_planet(&mut self, pos: Vector2<f32>){
        self.objs.bodies.push(Object::new(self.planet, pos, 50, 64., 1e13));
    }

    fn add_sun(&mut self, pos: Vector2<f32>){
        self.objs.bodies.push(Object::new(self.sun, pos, 100, 64., 2e14));
    }

    fn add_laser(&mut self, pos: Vector2<f32>, direction: f32){
        self.objs.projectiles.push(new_laser(self.laser, pos, direction));
    }
}

macro_rules! when_released{
    ($info:expr; $($key:ident => $b:block),+) => {
        for ke in $info.get_key_events(){
            match *ke{
                $((false, VirtualKeyCode::$key) => $b,)+
                _ => ()
            }
        }
    };
    ($info:expr;MOUSE; $($key:ident => $b:block),+) => {
        for ke in $info.get_mouse_events(){
            match *ke{
                $((false, MouseButton::$key) => $b,)+
                _ => ()
            }
        }
    };
}

impl<'a> Game for SpaceShooter<'a>{
    fn frame(&mut self, info: FrameInfo, mut drawer: Drawer) -> GameUpdate{
        self.deltas.push(info.delta);

        when_released!{info;
            Escape => {
                return GameUpdate::nothing().set_close(true)
            },
            M => {
                self.oobb = match self.oobb{
                    Bounce => Stop,
                    Stop => Wrap,
                    Wrap => Bounce
                };
                println!("OOBB changed to: {:?}", self.oobb);
            },
            N => {
                self.dbg_a = !self.dbg_a;
                println!("Turned debug arrows {}", if self.dbg_a{"on"}else{"off"});
            },
            C => {
                self.objs.bodies.clear();
                println!("Bodies cleared, new count: {}", self.objs.len());
            },
            K => {
                self.objs.projectiles.clear();
                println!("Projectiles cleared, new count: {}", self.objs.len());
            },
            O => {
                self.objs.players.clear();
                println!("Players cleared, new count: {}", self.objs.len());
            },
            P => {
                self.add_player();
                println!("Player added, new count: {}", self.objs.len());
            },
            Q => {
                let ObjSystem{players: ref a, bodies: ref b, projectiles: ref c} = self.objs;

                println!("{}::{}:{}:{}", self.deltas.capacity(), a.capacity(), b.capacity(), c.capacity());
            },
            Z => {
                let ObjSystem{players: ref mut a, bodies: ref mut b, projectiles: ref mut c} = self.objs;
                print!("{};{};{}->", a.capacity(), b.capacity(), c.capacity());
                a.shrink_to_fit();
                b.shrink_to_fit();
                c.shrink_to_fit();
                println!("{};{};{}", a.capacity(), b.capacity(), c.capacity());
            },
            X => {
                for x in self.objs.players.iter().chain(self.objs.bodies.iter()).chain(self.objs.projectiles.iter()){
                    println!("{:?}", &**x);
                }
            },
            Space => {
                let iter: Vec<_> = self.objs.players.iter().map(|x| {
                    let &InnerObject{pos, rot,..} = x.deref();
                    (pos, rot)
                }).collect();
                for &(pos, rot) in &iter{
                    self.add_laser(pos, rot);
                }
                println!("Laser{} added, new count: {}", if self.objs.players.len() == 1{""}else{"s"}, self.objs.len());
            }
        }

        when_released!{info;MOUSE;
            Left => {
                self.add_planet(info.mousepos.into());
                println!("Object added, new count: {}", self.objs.len());
            },
            Right => {
                self.add_sun(info.mousepos.into());
                println!("Object added, new count: {}", self.objs.len());
            }
        }

        drawer.clear(0., 0., 0.);
        self.objs.update(&info, &mut drawer, if self.dbg_a{Some(self.arrow)}else{None}, self.oobb);

        GameUpdate::nothing()
    }
}

#[derive(Default)]
pub struct ObjSystem<'a>{
    bodies     : Vec<Object<'a>>,
    players    : Vec<Object<'a>>,
    projectiles: Vec<Object<'a>>,
}

const G: f32 = 6.671281903963040991511534289e-11;
#[allow(dead_code)]
const G_OLD: f32 = 6.67384E-11;

use OutOfBoundsBehaviour::*;
use OutOfBoundsBehaviour;

fn gravity(x: &InnerObject, y: &InnerObject) -> Vector2<f32>{
    let r = x.pos.distance_to(y.pos);
    let g_force = (G * x.mass * y.mass) / (r * r);
    let dir_towards_body = x.pos.direction_to(y.pos);

    let force = Vector2::unit_vector(dir_towards_body) * g_force;
    if !(force.0.is_nan() || force.1.is_nan()){
        force
    }else{
        Vector2(0., 0.)
    }
}

impl<'a> ObjSystem<'a>{
    #[inline]
    pub fn new() -> Self{
        Default::default()
    }

    pub fn update(&mut self, info: &FrameInfo, drawer: &mut Drawer, arrow: Option<&Texture>, oobb: OutOfBoundsBehaviour){
        let (_pls, bs, _prs) = self.all_inners();
        let wh = drawer.graphics.get_h_size();
        let delta = info.delta as f32;

        for player in self.players.iter_mut(){
            let net_grav = bs.iter().fold(Vector2(0., 0.), |n_g, y| n_g + gravity(&player, y));

            let mut acceleration = 0.;
            is_down!{info;
                D, Right => {
                    player.rot -= 2. * delta
                },
                A, Left => {
                    player.rot += 2. * delta
                },
                S, Down => {
                    acceleration -= 52. * delta
                },
                W, Up => {
                    acceleration += 52. * delta;
                },
                LShift => {
                    acceleration *= 7.;
                }
            }

            let propulsion_force = Vector2::<f32>::unit_vector(player.rot) * acceleration;

            player.vel += propulsion_force;

            player.update(info, net_grav, wh, oobb);
            player.draw(drawer, arrow, net_grav, net_grav+propulsion_force);
        }
        for (i, body) in self.bodies.iter_mut().enumerate(){
            let net_grav = bs.iter().enumerate().filter_map(|(j, y)| if i==j{None}else{Some(y)}).fold(Vector2(0., 0.), |n_g, y| n_g + gravity(&body, y));

            body.update(info, net_grav, wh, oobb);
            body.draw(drawer, arrow, net_grav, net_grav);
        }
        for projectile in self.projectiles.iter_mut(){
            let net_grav = bs.iter().fold(Vector2(0., 0.), |n_g, y| n_g + gravity(&projectile, y));

            projectile.rot = projectile.vel.direction();

            projectile.update(info, net_grav, wh, oobb);
            projectile.draw(drawer, arrow, net_grav, net_grav);
        }
    }

    pub fn all_inners(&self) -> (Vec<InnerObject>, Vec<InnerObject>, Vec<InnerObject>){
        fn inners(x: &Vec<Object>) -> Vec<InnerObject>{
            x.iter().map(|x| **x).collect()
        }

        (inners(&self.players), inners(&self.bodies), inners(&self.projectiles))
    }

    pub fn len(&self) -> usize{
        self.players.len() + self.bodies.len() + self.projectiles.len()
    }
}
<commit_msg>Skip the first two deltas<commit_after>use ::korome::*;
use ::obj::*;

use std::ops::Deref;

pub struct SpaceShooter<'a>{
    objs: ObjSystem<'a>,
    player: &'a Texture,
    sun   : &'a Texture,
    planet: &'a Texture,
    arrow : &'a Texture,
    laser : &'a Texture,
    oobb  : OutOfBoundsBehaviour,
    dbg_a : bool,
    deltas: Vec<f64>,
}

use std::ops::Drop;

impl<'a> Drop for SpaceShooter<'a>{
    fn drop(&mut self){
        use std::fs::File;
        use std::io::{Write, BufWriter};

        let file = File::create("deltas.log").unwrap();
        let mut writer = BufWriter::new(file);

        let (len, mut min, mut max, mut sum) = (self.deltas.len(), ::std::f64::MAX, 0f64, 0.);

        // Skip the first two 'cause they're normally too high.
        for n in self.deltas.drain(..).skip(2){
            min = min.min(n);
            max = max.max(n);
            sum += n;

            writer.write_fmt(format_args!("{}s ~ {}fps\n", n, 1./n)).unwrap()
        }

        let avg = sum/len as f64;

        println!("Total  : {}s", sum);
        println!("Best   : {}s ~ {}fps", min, 1./min);
        println!("Worst  : {}s ~ {}fps", max, 1./max);
        println!("Average: {}s ~ {}fps", avg, 1./avg);
    }
}

impl<'a> SpaceShooter<'a>{
    pub fn new(planet: &'a Texture, player: &'a Texture, sun: &'a Texture, arrow: &'a Texture, laser: &'a Texture) -> Self{
        let mut objs = ObjSystem::new();
        objs.players.push(new_player(player));

        SpaceShooter{
            player: player,
            sun   : sun,
            objs  : objs,
            planet: planet,
            arrow : arrow,
            laser : laser,
            oobb  : Bounce,
            dbg_a : true,
            deltas: Vec::with_capacity(10_000),
        }
    }

    fn add_player(&mut self){
        self.objs.players.push(new_player(self.player))
    }

    fn add_planet(&mut self, pos: Vector2<f32>){
        self.objs.bodies.push(Object::new(self.planet, pos, 50, 64., 1e13));
    }

    fn add_sun(&mut self, pos: Vector2<f32>){
        self.objs.bodies.push(Object::new(self.sun, pos, 100, 64., 2e14));
    }

    fn add_laser(&mut self, pos: Vector2<f32>, direction: f32){
        self.objs.projectiles.push(new_laser(self.laser, pos, direction));
    }
}

macro_rules! when_released{
    ($info:expr; $($key:ident => $b:block),+) => {
        for ke in $info.get_key_events(){
            match *ke{
                $((false, VirtualKeyCode::$key) => $b,)+
                _ => ()
            }
        }
    };
    ($info:expr;MOUSE; $($key:ident => $b:block),+) => {
        for ke in $info.get_mouse_events(){
            match *ke{
                $((false, MouseButton::$key) => $b,)+
                _ => ()
            }
        }
    };
}

impl<'a> Game for SpaceShooter<'a>{
    fn frame(&mut self, info: FrameInfo, mut drawer: Drawer) -> GameUpdate{
        self.deltas.push(info.delta);

        when_released!{info;
            Escape => {
                return GameUpdate::nothing().set_close(true)
            },
            M => {
                self.oobb = match self.oobb{
                    Bounce => Stop,
                    Stop => Wrap,
                    Wrap => Bounce
                };
                println!("OOBB changed to: {:?}", self.oobb);
            },
            N => {
                self.dbg_a = !self.dbg_a;
                println!("Turned debug arrows {}", if self.dbg_a{"on"}else{"off"});
            },
            C => {
                self.objs.bodies.clear();
                println!("Bodies cleared, new count: {}", self.objs.len());
            },
            K => {
                self.objs.projectiles.clear();
                println!("Projectiles cleared, new count: {}", self.objs.len());
            },
            O => {
                self.objs.players.clear();
                println!("Players cleared, new count: {}", self.objs.len());
            },
            P => {
                self.add_player();
                println!("Player added, new count: {}", self.objs.len());
            },
            Q => {
                let ObjSystem{players: ref a, bodies: ref b, projectiles: ref c} = self.objs;

                println!("{}::{}:{}:{}", self.deltas.capacity(), a.capacity(), b.capacity(), c.capacity());
            },
            Z => {
                let ObjSystem{players: ref mut a, bodies: ref mut b, projectiles: ref mut c} = self.objs;
                print!("{};{};{}->", a.capacity(), b.capacity(), c.capacity());
                a.shrink_to_fit();
                b.shrink_to_fit();
                c.shrink_to_fit();
                println!("{};{};{}", a.capacity(), b.capacity(), c.capacity());
            },
            X => {
                for x in self.objs.players.iter().chain(self.objs.bodies.iter()).chain(self.objs.projectiles.iter()){
                    println!("{:?}", &**x);
                }
            },
            Space => {
                let iter: Vec<_> = self.objs.players.iter().map(|x| {
                    let &InnerObject{pos, rot,..} = x.deref();
                    (pos, rot)
                }).collect();
                for &(pos, rot) in &iter{
                    self.add_laser(pos, rot);
                }
                println!("Laser{} added, new count: {}", if self.objs.players.len() == 1{""}else{"s"}, self.objs.len());
            }
        }

        when_released!{info;MOUSE;
            Left => {
                self.add_planet(info.mousepos.into());
                println!("Object added, new count: {}", self.objs.len());
            },
            Right => {
                self.add_sun(info.mousepos.into());
                println!("Object added, new count: {}", self.objs.len());
            }
        }

        drawer.clear(0., 0., 0.);
        self.objs.update(&info, &mut drawer, if self.dbg_a{Some(self.arrow)}else{None}, self.oobb);

        GameUpdate::nothing()
    }
}

#[derive(Default)]
pub struct ObjSystem<'a>{
    bodies     : Vec<Object<'a>>,
    players    : Vec<Object<'a>>,
    projectiles: Vec<Object<'a>>,
}

const G: f32 = 6.671281903963040991511534289e-11;
#[allow(dead_code)]
const G_OLD: f32 = 6.67384E-11;

use OutOfBoundsBehaviour::*;
use OutOfBoundsBehaviour;

fn gravity(x: &InnerObject, y: &InnerObject) -> Vector2<f32>{
    let r = x.pos.distance_to(y.pos);
    let g_force = (G * x.mass * y.mass) / (r * r);
    let dir_towards_body = x.pos.direction_to(y.pos);

    let force = Vector2::unit_vector(dir_towards_body) * g_force;
    if !(force.0.is_nan() || force.1.is_nan()){
        force
    }else{
        Vector2(0., 0.)
    }
}

impl<'a> ObjSystem<'a>{
    #[inline]
    pub fn new() -> Self{
        Default::default()
    }

    pub fn update(&mut self, info: &FrameInfo, drawer: &mut Drawer, arrow: Option<&Texture>, oobb: OutOfBoundsBehaviour){
        let (_pls, bs, _prs) = self.all_inners();
        let wh = drawer.graphics.get_h_size();
        let delta = info.delta as f32;

        for player in self.players.iter_mut(){
            let net_grav = bs.iter().fold(Vector2(0., 0.), |n_g, y| n_g + gravity(&player, y));

            let mut acceleration = 0.;
            is_down!{info;
                D, Right => {
                    player.rot -= 2. * delta
                },
                A, Left => {
                    player.rot += 2. * delta
                },
                S, Down => {
                    acceleration -= 52. * delta
                },
                W, Up => {
                    acceleration += 52. * delta;
                },
                LShift => {
                    acceleration *= 7.;
                }
            }

            let propulsion_force = Vector2::<f32>::unit_vector(player.rot) * acceleration;

            player.vel += propulsion_force;

            player.update(info, net_grav, wh, oobb);
            player.draw(drawer, arrow, net_grav, net_grav+propulsion_force);
        }
        for (i, body) in self.bodies.iter_mut().enumerate(){
            let net_grav = bs.iter().enumerate().filter_map(|(j, y)| if i==j{None}else{Some(y)}).fold(Vector2(0., 0.), |n_g, y| n_g + gravity(&body, y));

            body.update(info, net_grav, wh, oobb);
            body.draw(drawer, arrow, net_grav, net_grav);
        }
        for projectile in self.projectiles.iter_mut(){
            let net_grav = bs.iter().fold(Vector2(0., 0.), |n_g, y| n_g + gravity(&projectile, y));

            projectile.rot = projectile.vel.direction();

            projectile.update(info, net_grav, wh, oobb);
            projectile.draw(drawer, arrow, net_grav, net_grav);
        }
    }

    pub fn all_inners(&self) -> (Vec<InnerObject>, Vec<InnerObject>, Vec<InnerObject>){
        fn inners(x: &Vec<Object>) -> Vec<InnerObject>{
            x.iter().map(|x| **x).collect()
        }

        (inners(&self.players), inners(&self.bodies), inners(&self.projectiles))
    }

    pub fn len(&self) -> usize{
        self.players.len() + self.bodies.len() + self.projectiles.len()
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Transactions

use byteorder::{ByteOrder, BigEndian};
use secp::{self, Secp256k1, Message, Signature};
use secp::pedersen::{RangeProof, Commitment};

use core::Committed;
use core::MerkleRow;
use core::hash::{Hash, Hashed};
use ser::{self, Reader, Writer, Readable, Writeable};

bitflags! {
    /// Options for a kernel's structure or use
    pub flags KernelFeatures: u8 {
        /// No flags
        const DEFAULT_KERNEL = 0b00000000,
        /// Kernel matching a coinbase output
        const COINBASE_KERNEL = 0b00000001,
    }
}

/// A proof that a transaction sums to zero. Includes both the transaction's
/// Pedersen commitment and the signature, that guarantees that the commitments
/// amount to zero. The signature signs the fee, which is retained for
/// signature validation.
#[derive(Debug, Clone, PartialEq)]
pub struct TxKernel {
	/// Options for a kernel's structure or use
	pub features: KernelFeatures,
	/// Remainder of the sum of all transaction commitments. If the transaction
	/// is well formed, amounts components should sum to zero and the excess
	/// is hence a valid public key.
	pub excess: Commitment,
	/// The signature proving the excess is a valid public key, which signs
	/// the transaction fee.
	pub excess_sig: Vec<u8>,
	/// Fee originally included in the transaction this proof is for.
	pub fee: u64,
}

impl Writeable for TxKernel {
	fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		ser_multiwrite!(writer,
		                [write_u8, self.features.bits()],
		                [write_fixed_bytes, &self.excess],
		                [write_bytes, &self.excess_sig],
		                [write_u64, self.fee]);
		Ok(())
	}
}

impl Readable for TxKernel {
	fn read(reader: &mut Reader) -> Result<TxKernel, ser::Error> {
		Ok(TxKernel {
			features:
				KernelFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?,
			excess: Commitment::read(reader)?,
			excess_sig: reader.read_vec()?,
			fee: reader.read_u64()?,
		})
	}
}

impl TxKernel {
	/// Verify the transaction proof validity. Entails handling the commitment
	/// as a public key and checking the signature verifies with the fee as
	/// message.
	pub fn verify(&self, secp: &Secp256k1) -> Result<(), secp::Error> {
		let msg = try!(Message::from_slice(&u64_to_32bytes(self.fee)));
		let pubk = try!(self.excess.to_pubkey(secp));
		let sig = try!(Signature::from_der(secp, &self.excess_sig));
		secp.verify(&msg, &sig, &pubk)
	}
}

/// A transaction
#[derive(Debug, Clone)]
pub struct Transaction {
	/// Set of inputs spent by the transaction.
	pub inputs: Vec<Input>,
	/// Set of outputs the transaction produces.
	pub outputs: Vec<Output>,
	/// Fee paid by the transaction.
	pub fee: u64,
	/// The signature proving the excess is a valid public key, which signs
	/// the transaction fee.
	pub excess_sig: Vec<u8>,
}

/// Implementation of Writeable for a fully blinded transaction, defines how to
/// write the transaction as binary.
impl Writeable for Transaction {
	fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		ser_multiwrite!(writer,
		                [write_u64, self.fee],
		                [write_bytes, &self.excess_sig],
		                [write_u64, self.inputs.len() as u64],
		                [write_u64, self.outputs.len() as u64]);
		for inp in &self.inputs {
			try!(inp.write(writer));
		}
		for out in &self.outputs {
			try!(out.write(writer));
		}
		Ok(())
	}
}

/// Implementation of Readable for a transaction, defines how to read a full
/// transaction from a binary stream.
impl Readable for Transaction {
	fn read(reader: &mut Reader) -> Result<Transaction, ser::Error> {
		let (fee, excess_sig, input_len, output_len) =
			ser_multiread!(reader, read_u64, read_vec, read_u64, read_u64);

		let inputs = try!((0..input_len).map(|_| Input::read(reader)).collect());
		let outputs = try!((0..output_len).map(|_| Output::read(reader)).collect());

		Ok(Transaction {
			fee: fee,
			excess_sig: excess_sig,
			inputs: inputs,
			outputs: outputs,
			..Default::default()
		})
	}
}

impl Committed for Transaction {
	fn inputs_committed(&self) -> &Vec<Input> {
		&self.inputs
	}
	fn outputs_committed(&self) -> &Vec<Output> {
		&self.outputs
	}
	fn overage(&self) -> i64 {
		(self.fee as i64)
	}
}

impl Default for Transaction {
	fn default() -> Transaction {
		Transaction::empty()
	}
}

impl Transaction {
	/// Creates a new empty transaction (no inputs or outputs, zero fee).
	pub fn empty() -> Transaction {
		Transaction {
			fee: 0,
			excess_sig: vec![],
			inputs: vec![],
			outputs: vec![],
		}
	}

	/// Creates a new transaction initialized with the provided inputs,
	/// outputs and fee.
	pub fn new(inputs: Vec<Input>, outputs: Vec<Output>, fee: u64) -> Transaction {
		Transaction {
			fee: fee,
			excess_sig: vec![],
			inputs: inputs,
			outputs: outputs,
		}
	}

	/// Builds a new transaction with the provided inputs added. Existing
	/// inputs, if any, are kept intact.
	pub fn with_input(self, input: Input) -> Transaction {
		let mut new_ins = self.inputs;
		new_ins.push(input);
		Transaction { inputs: new_ins, ..self }
	}

	/// Builds a new transaction with the provided output added. Existing
	/// outputs, if any, are kept intact.
	pub fn with_output(self, output: Output) -> Transaction {
		let mut new_outs = self.outputs;
		new_outs.push(output);
		Transaction { outputs: new_outs, ..self }
	}

	/// Builds a new transaction with the provided fee.
	pub fn with_fee(self, fee: u64) -> Transaction {
		Transaction { fee: fee, ..self }
	}

	/// The verification for a MimbleWimble transaction involves getting the
	/// excess of summing all commitments and using it as a public key
	/// to verify the embedded signature. The rational is that if the values
	/// sum to zero as they should in r.G + v.H then only k.G the excess
	/// of the sum of r.G should be left. And r.G is the definition of a
	/// public key generated using r as a private key.
	pub fn verify_sig(&self, secp: &Secp256k1) -> Result<TxKernel, secp::Error> {
		let rsum = self.sum_commitments(secp)?;

		// pretend the sum is a public key (which it is, being of the form r.G) and
		// verify the transaction sig with it
		let pubk = rsum.to_pubkey(secp)?;
		let msg = Message::from_slice(&u64_to_32bytes(self.fee))?;
		let sig = Signature::from_der(secp, &self.excess_sig)?;
		secp.verify(&msg, &sig, &pubk)?;

		Ok(TxKernel {
			features: DEFAULT_KERNEL,
			excess: rsum,
			excess_sig: self.excess_sig.clone(),
			fee: self.fee,
		})
	}

	/// Validates all relevant parts of a fully built transaction. Checks the
	/// excess value against the signature as well as range proofs for each
	/// output.
	pub fn validate(&self, secp: &Secp256k1) -> Result<TxKernel, secp::Error> {
		for out in &self.outputs {
			out.verify_proof(secp)?;
		}
		self.verify_sig(secp)
	}
}

/// A transaction input, mostly a reference to an output being spent by the
/// transaction.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Input(pub Commitment);

/// Implementation of Writeable for a transaction Input, defines how to write
/// an Input as binary.
impl Writeable for Input {
	fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		writer.write_fixed_bytes(&self.0)
	}
}

/// Implementation of Readable for a transaction Input, defines how to read
/// an Input from a binary stream.
impl Readable for Input {
	fn read(reader: &mut Reader) -> Result<Input, ser::Error> {
		Ok(Input(Commitment::read(reader)?))
	}
}

/// The input for a transaction, which spends a pre-existing output. The input
/// commitment is a reproduction of the commitment of the output it's spending.
impl Input {
	/// Extracts the referenced commitment from a transaction output
	pub fn commitment(&self) -> Commitment {
		self.0
	}
}

bitflags! {
    /// Options for block validation
    #[derive(Serialize, Deserialize)]
    pub flags OutputFeatures: u8 {
        /// No flags
        const DEFAULT_OUTPUT = 0b00000000,
        /// Output is a coinbase output, has fixed amount and must not be spent until maturity
        const COINBASE_OUTPUT = 0b00000001,
    }
}

/// Output for a transaction, defining the new ownership of coins that are being
/// transferred. The commitment is a blinded value for the output while the
/// range proof guarantees the commitment includes a positive value without
/// overflow and the ownership of the private key.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub struct Output {
	/// Options for an output's structure or use
	pub features: OutputFeatures,
	/// The homomorphic commitment representing the output's amount
	pub commit: Commitment,
	/// A proof that the commitment is in the right range
	pub proof: RangeProof,
}

/// Implementation of Writeable for a transaction Output, defines how to write
/// an Output as binary.
impl Writeable for Output {
	fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		ser_multiwrite!(writer,
		                [write_u8, self.features.bits()],
		                [write_fixed_bytes, &self.commit]);
		// The hash of an output doesn't include the range proof
		if writer.serialization_mode() == ser::SerializationMode::Full {
			writer.write_bytes(&self.proof)?
		}
		Ok(())
	}
}

/// Implementation of Readable for a transaction Output, defines how to read
/// an Output from a binary stream.
impl Readable for Output {
	fn read(reader: &mut Reader) -> Result<Output, ser::Error> {
		Ok(Output {
			features:
				OutputFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?,
			commit: Commitment::read(reader)?,
			proof: RangeProof::read(reader)?,
		})
	}
}

impl Output {
	/// Commitment for the output
	pub fn commitment(&self) -> Commitment {
		self.commit
	}

	/// Range proof for the output
	pub fn proof(&self) -> RangeProof {
		self.proof
	}

	/// Validates the range proof using the commitment
	pub fn verify_proof(&self, secp: &Secp256k1) -> Result<(), secp::Error> {
		secp.verify_range_proof(self.commit, self.proof).map(|_| ())
	}
}

/// Utility function to calculate the Merkle root of vectors of inputs and
/// outputs.
pub fn merkle_inputs_outputs(inputs: &Vec<Input>, outputs: &Vec<Output>) -> Hash {
	let mut all_hs = map_vec!(inputs, |inp| inp.hash());
	all_hs.append(&mut map_vec!(outputs, |out| out.hash()));
	MerkleRow::new(all_hs).root()
}

fn u64_to_32bytes(n: u64) -> [u8; 32] {
	let mut bytes = [0; 32];
	BigEndian::write_u64(&mut bytes[24..32], n);
	bytes
}
<commit_msg>Checking rangeproof explanatory comment (#120)<commit_after>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Transactions

use byteorder::{ByteOrder, BigEndian};
use secp::{self, Secp256k1, Message, Signature};
use secp::pedersen::{RangeProof, Commitment};

use core::Committed;
use core::MerkleRow;
use core::hash::{Hash, Hashed};
use ser::{self, Reader, Writer, Readable, Writeable};

bitflags! {
    /// Options for a kernel's structure or use
    pub flags KernelFeatures: u8 {
        /// No flags
        const DEFAULT_KERNEL = 0b00000000,
        /// Kernel matching a coinbase output
        const COINBASE_KERNEL = 0b00000001,
    }
}

/// A proof that a transaction sums to zero. Includes both the transaction's
/// Pedersen commitment and the signature, that guarantees that the commitments
/// amount to zero. The signature signs the fee, which is retained for
/// signature validation.
#[derive(Debug, Clone, PartialEq)]
pub struct TxKernel {
	/// Options for a kernel's structure or use
	pub features: KernelFeatures,
	/// Remainder of the sum of all transaction commitments. If the transaction
	/// is well formed, amounts components should sum to zero and the excess
	/// is hence a valid public key.
	pub excess: Commitment,
	/// The signature proving the excess is a valid public key, which signs
	/// the transaction fee.
	pub excess_sig: Vec<u8>,
	/// Fee originally included in the transaction this proof is for.
	pub fee: u64,
}

impl Writeable for TxKernel {
	fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		ser_multiwrite!(writer,
		                [write_u8, self.features.bits()],
		                [write_fixed_bytes, &self.excess],
		                [write_bytes, &self.excess_sig],
		                [write_u64, self.fee]);
		Ok(())
	}
}

impl Readable for TxKernel {
	fn read(reader: &mut Reader) -> Result<TxKernel, ser::Error> {
		Ok(TxKernel {
			features:
				KernelFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?,
			excess: Commitment::read(reader)?,
			excess_sig: reader.read_vec()?,
			fee: reader.read_u64()?,
		})
	}
}

impl TxKernel {
	/// Verify the transaction proof validity. Entails handling the commitment
	/// as a public key and checking the signature verifies with the fee as
	/// message.
	pub fn verify(&self, secp: &Secp256k1) -> Result<(), secp::Error> {
		let msg = try!(Message::from_slice(&u64_to_32bytes(self.fee)));
		let pubk = try!(self.excess.to_pubkey(secp));
		let sig = try!(Signature::from_der(secp, &self.excess_sig));
		secp.verify(&msg, &sig, &pubk)
	}
}

/// A transaction
#[derive(Debug, Clone)]
pub struct Transaction {
	/// Set of inputs spent by the transaction.
	pub inputs: Vec<Input>,
	/// Set of outputs the transaction produces.
	pub outputs: Vec<Output>,
	/// Fee paid by the transaction.
	pub fee: u64,
	/// The signature proving the excess is a valid public key, which signs
	/// the transaction fee.
	pub excess_sig: Vec<u8>,
}

/// Implementation of Writeable for a fully blinded transaction, defines how to
/// write the transaction as binary.
impl Writeable for Transaction {
	fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		ser_multiwrite!(writer,
		                [write_u64, self.fee],
		                [write_bytes, &self.excess_sig],
		                [write_u64, self.inputs.len() as u64],
		                [write_u64, self.outputs.len() as u64]);
		for inp in &self.inputs {
			try!(inp.write(writer));
		}
		for out in &self.outputs {
			try!(out.write(writer));
		}
		Ok(())
	}
}

/// Implementation of Readable for a transaction, defines how to read a full
/// transaction from a binary stream.
impl Readable for Transaction {
	fn read(reader: &mut Reader) -> Result<Transaction, ser::Error> {
		let (fee, excess_sig, input_len, output_len) =
			ser_multiread!(reader, read_u64, read_vec, read_u64, read_u64);

		let inputs = try!((0..input_len).map(|_| Input::read(reader)).collect());
		let outputs = try!((0..output_len).map(|_| Output::read(reader)).collect());

		Ok(Transaction {
			fee: fee,
			excess_sig: excess_sig,
			inputs: inputs,
			outputs: outputs,
			..Default::default()
		})
	}
}

impl Committed for Transaction {
	fn inputs_committed(&self) -> &Vec<Input> {
		&self.inputs
	}
	fn outputs_committed(&self) -> &Vec<Output> {
		&self.outputs
	}
	fn overage(&self) -> i64 {
		(self.fee as i64)
	}
}

impl Default for Transaction {
	fn default() -> Transaction {
		Transaction::empty()
	}
}

impl Transaction {
	/// Creates a new empty transaction (no inputs or outputs, zero fee).
	pub fn empty() -> Transaction {
		Transaction {
			fee: 0,
			excess_sig: vec![],
			inputs: vec![],
			outputs: vec![],
		}
	}

	/// Creates a new transaction initialized with the provided inputs,
	/// outputs and fee.
	pub fn new(inputs: Vec<Input>, outputs: Vec<Output>, fee: u64) -> Transaction {
		Transaction {
			fee: fee,
			excess_sig: vec![],
			inputs: inputs,
			outputs: outputs,
		}
	}

	/// Builds a new transaction with the provided inputs added. Existing
	/// inputs, if any, are kept intact.
	pub fn with_input(self, input: Input) -> Transaction {
		let mut new_ins = self.inputs;
		new_ins.push(input);
		Transaction { inputs: new_ins, ..self }
	}

	/// Builds a new transaction with the provided output added. Existing
	/// outputs, if any, are kept intact.
	pub fn with_output(self, output: Output) -> Transaction {
		let mut new_outs = self.outputs;
		new_outs.push(output);
		Transaction { outputs: new_outs, ..self }
	}

	/// Builds a new transaction with the provided fee.
	pub fn with_fee(self, fee: u64) -> Transaction {
		Transaction { fee: fee, ..self }
	}

	/// The verification for a MimbleWimble transaction involves getting the
	/// excess of summing all commitments and using it as a public key
	/// to verify the embedded signature. The rational is that if the values
	/// sum to zero as they should in r.G + v.H then only k.G the excess
	/// of the sum of r.G should be left. And r.G is the definition of a
	/// public key generated using r as a private key.
	pub fn verify_sig(&self, secp: &Secp256k1) -> Result<TxKernel, secp::Error> {
		let rsum = self.sum_commitments(secp)?;

		// pretend the sum is a public key (which it is, being of the form r.G) and
		// verify the transaction sig with it
		let pubk = rsum.to_pubkey(secp)?;
		let msg = Message::from_slice(&u64_to_32bytes(self.fee))?;
		let sig = Signature::from_der(secp, &self.excess_sig)?;
		secp.verify(&msg, &sig, &pubk)?;

		Ok(TxKernel {
			features: DEFAULT_KERNEL,
			excess: rsum,
			excess_sig: self.excess_sig.clone(),
			fee: self.fee,
		})
	}

	/// Validates all relevant parts of a fully built transaction. Checks the
	/// excess value against the signature as well as range proofs for each
	/// output.
	pub fn validate(&self, secp: &Secp256k1) -> Result<TxKernel, secp::Error> {
		for out in &self.outputs {
			out.verify_proof(secp)?;
		}
		self.verify_sig(secp)
	}
}

/// A transaction input, mostly a reference to an output being spent by the
/// transaction.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Input(pub Commitment);

/// Implementation of Writeable for a transaction Input, defines how to write
/// an Input as binary.
impl Writeable for Input {
	fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		writer.write_fixed_bytes(&self.0)
	}
}

/// Implementation of Readable for a transaction Input, defines how to read
/// an Input from a binary stream.
impl Readable for Input {
	fn read(reader: &mut Reader) -> Result<Input, ser::Error> {
		Ok(Input(Commitment::read(reader)?))
	}
}

/// The input for a transaction, which spends a pre-existing output. The input
/// commitment is a reproduction of the commitment of the output it's spending.
impl Input {
	/// Extracts the referenced commitment from a transaction output
	pub fn commitment(&self) -> Commitment {
		self.0
	}
}

bitflags! {
    /// Options for block validation
    #[derive(Serialize, Deserialize)]
    pub flags OutputFeatures: u8 {
        /// No flags
        const DEFAULT_OUTPUT = 0b00000000,
        /// Output is a coinbase output, has fixed amount and must not be spent until maturity
        const COINBASE_OUTPUT = 0b00000001,
    }
}

/// Output for a transaction, defining the new ownership of coins that are being
/// transferred. The commitment is a blinded value for the output while the
/// range proof guarantees the commitment includes a positive value without
/// overflow and the ownership of the private key.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub struct Output {
	/// Options for an output's structure or use
	pub features: OutputFeatures,
	/// The homomorphic commitment representing the output's amount
	pub commit: Commitment,
	/// A proof that the commitment is in the right range
	pub proof: RangeProof,
}

/// Implementation of Writeable for a transaction Output, defines how to write
/// an Output as binary.
impl Writeable for Output {
	fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		ser_multiwrite!(writer,
		                [write_u8, self.features.bits()],
		                [write_fixed_bytes, &self.commit]);
		// The hash of an output doesn't include the range proof
		if writer.serialization_mode() == ser::SerializationMode::Full {
			writer.write_bytes(&self.proof)?
		}
		Ok(())
	}
}

/// Implementation of Readable for a transaction Output, defines how to read
/// an Output from a binary stream.
impl Readable for Output {
	fn read(reader: &mut Reader) -> Result<Output, ser::Error> {
		Ok(Output {
			features:
				OutputFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?,
			commit: Commitment::read(reader)?,
			proof: RangeProof::read(reader)?,
		})
	}
}

impl Output {
	/// Commitment for the output
	pub fn commitment(&self) -> Commitment {
		self.commit
	}

	/// Range proof for the output
	pub fn proof(&self) -> RangeProof {
		self.proof
	}

	/// Validates the range proof using the commitment
	pub fn verify_proof(&self, secp: &Secp256k1) -> Result<(), secp::Error> {
		/// secp.verify returns range if and only if both min_value and max_value less than 2^64
                /// since group order is much larger (~2^256) we can be sure overflow is not the case
		secp.verify_range_proof(self.commit, self.proof).map(|_| ())
	}
}

/// Utility function to calculate the Merkle root of vectors of inputs and
/// outputs.
pub fn merkle_inputs_outputs(inputs: &Vec<Input>, outputs: &Vec<Output>) -> Hash {
	let mut all_hs = map_vec!(inputs, |inp| inp.hash());
	all_hs.append(&mut map_vec!(outputs, |out| out.hash()));
	MerkleRow::new(all_hs).root()
}

fn u64_to_32bytes(n: u64) -> [u8; 32] {
	let mut bytes = [0; 32];
	BigEndian::write_u64(&mut bytes[24..32], n);
	bytes
}
<|endoftext|>