<commit_before>extern crate libc;
use std::ffi::CString;
use std::mem::size_of;

extern crate rpgffi as pg;

// Implementation of initialization and callbacks.

pub unsafe extern "C" fn init(cb: *mut pg::OutputPluginCallbacks) {
    (*cb).startup_cb = Some(startup);
    (*cb).begin_cb = Some(begin);
    (*cb).change_cb = Some(change);
    (*cb).commit_cb = Some(commit);
    (*cb).shutdown_cb = Some(shutdown);
}

unsafe extern "C" fn startup(ctx: *mut pg::Struct_LogicalDecodingContext,
                             options: *mut pg::OutputPluginOptions,
                             _is_init: pg::_bool) {
    use pg::Enum_OutputPluginOutputType::*;
    let last_relid = pg::palloc0(size_of::<pg::Oid>() as u64);
    (*ctx).output_plugin_private = last_relid;
    (*options).output_type = OUTPUT_PLUGIN_TEXTUAL_OUTPUT;
}

unsafe extern "C" fn begin(ctx: *mut pg::Struct_LogicalDecodingContext,
                           txn: *mut pg::ReorderBufferTXN) {
    let s = CString::new("{ \"begin\": %u }").unwrap();
    pg::OutputPluginPrepareWrite(ctx, CTRUE);
    pg::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid);
    pg::OutputPluginWrite(ctx, CTRUE);
}

unsafe extern "C" fn change(ctx: *mut pg::Struct_LogicalDecodingContext,
                            _txn: *mut pg::ReorderBufferTXN,
                            relation: pg::Relation,
                            change: *mut pg::ReorderBufferChange) {
    let relid = (*relation).rd_id;
    let last_relid: *mut pg::Oid =
        (*ctx).output_plugin_private as *mut pg::Oid;
    if *last_relid != relid {
        pg::OutputPluginPrepareWrite(ctx, CFALSE);
        append_schema(relation, (*ctx).out);
        pg::OutputPluginWrite(ctx, CFALSE);
        *last_relid = relid;
    }
    pg::OutputPluginPrepareWrite(ctx, CTRUE);
    append_change(relation, change, (*ctx).out);
    pg::OutputPluginWrite(ctx, CTRUE);
}

unsafe extern "C" fn commit(ctx: *mut pg::Struct_LogicalDecodingContext,
                            txn: *mut pg::ReorderBufferTXN,
                            _lsn: pg::XLogRecPtr) {
    let s = CString::new("{ \"commit\": %u, \"t\": \"%s\" }").unwrap();
    let t = pg::timestamptz_to_str((*txn).commit_time);
    pg::OutputPluginPrepareWrite(ctx, CTRUE);
    pg::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid, t);
    pg::OutputPluginWrite(ctx, CTRUE);
    let last_relid: *mut pg::Oid =
        (*ctx).output_plugin_private as *mut pg::Oid;
    *last_relid = 0;
}

unsafe extern "C" fn shutdown(ctx: *mut pg::Struct_LogicalDecodingContext) {
    pg::pfree((*ctx).output_plugin_private);
}

trait PGAppend<T> {
    unsafe fn add_str(self, T);
    unsafe fn add_json(self, T);
}

impl<'a> PGAppend<&'a str> for pg::StringInfo {
    unsafe fn add_str(self, t: &'a str) {
        pg::appendStringInfoString(self, CString::new(t).unwrap().as_ptr());
    }
    unsafe fn add_json(self, t: &'a str) {
        pg::escape_json(self, CString::new(t).unwrap().as_ptr());
    }
}

impl PGAppend<*mut i8> for pg::StringInfo {
    unsafe fn add_str(self, t: *mut i8) {
        pg::appendStringInfoString(self, t);
    }
    unsafe fn add_json(self, t: *mut i8) {
        pg::escape_json(self, t);
    }
}

unsafe fn append_change(relation: pg::Relation,
                        change: *mut pg::ReorderBufferChange,
                        out: pg::StringInfo) {
    use pg::Enum_ReorderBufferChangeType::*;
    let relid = (*relation).rd_id;
    let name = pg::get_rel_name(relid);
    let ns = pg::get_namespace_name(pg::get_rel_namespace(relid));
    let qualified_name = pg::quote_qualified_identifier(ns, name);
    let tuple_desc = (*relation).rd_att;
    let tuples = (*change).data.tp();
    let tuple_new = (*tuples).newtuple;
    let tuple_old = (*tuples).oldtuple;
    let token = match (*change).action {
        REORDER_BUFFER_CHANGE_INSERT => "insert",
        REORDER_BUFFER_CHANGE_UPDATE => "update",
        REORDER_BUFFER_CHANGE_DELETE => "delete",
        _ => panic!("Unrecognized change action!"),
    };
    out.add_str("{ ");
    out.add_json(token);
    out.add_str(": ");
    append_tuple_buf_as_json(tuple_new, tuple_desc, out);
    if !tuple_old.is_null() {
        out.add_str(", \"@\": ");
        append_tuple_buf_as_json(tuple_old, tuple_desc, out);
    }
    out.add_str(", ");
    out.add_json("table");
    out.add_str(": ");
    out.add_json(qualified_name);
    out.add_str(" }");
}

unsafe fn append_tuple_buf_as_json(data: *mut pg::ReorderBufferTupleBuf,
                                   desc: pg::TupleDesc,
                                   out: pg::StringInfo) {
    if !data.is_null() {
        let heap_tuple = &mut (*data).tuple;
        let n = (*desc).natts as usize;
        let attrs = (*desc).attrs;

        // Pull out every single field to check for stale TOAST.
        let mut datums: Vec<pg::Datum> = Vec::new();
        let mut nulls: Vec<pg::_bool> = Vec::new();
        datums.resize(n, 0);
        nulls.resize(n, CFALSE);
        pg::heap_deform_tuple(heap_tuple,
                              desc,
                              datums.as_mut_ptr(),
                              nulls.as_mut_ptr());

        let mut skip: Vec<pg::Form_pg_attribute> = Vec::with_capacity(n);

        for i in 0..n {
            let datum: pg::Datum = datums[i];
            let attr = *attrs.offset(i as isize);
            if is_stale_toast(datum) && (*attr).attisdropped == CFALSE {
                skip.push(attr);
            }
        }

        // Mark as dropped to trick row_to_json().
        for attr in &mut skip {
            (**attr).attisdropped = CTRUE;
        }

        let datum = pg::heap_copy_tuple_as_datum(heap_tuple, desc);
        let empty_oid: pg::Oid = 0;
        let json =
            pg::DirectFunctionCall1Coll(Some(row_to_json), empty_oid, datum);

        // Set back to true because who knows how else these attrs, which are
        // part of the passed in tuple description, are being used.
        for attr in &mut skip {
            (**attr).attisdropped = CFALSE;
        }

        let ptr = json as *const pg::Struct_varlena;
        let text = pg::text_to_cstring(ptr);
        pg::appendStringInfoString(out, text);
    } else {
        out.add_str("{}");
    }
}

unsafe fn append_schema(relation: pg::Relation, out: pg::StringInfo) {
    let relid = (*relation).rd_id;
    let tupdesc = (*relation).rd_att;
    let name = pg::get_rel_name(relid);
    let ns = pg::get_namespace_name(pg::get_rel_namespace(relid));
    let qualified_name = pg::quote_qualified_identifier(ns, name);
    out.add_str("{ ");
    out.add_json("schema");
    out.add_str(": ");
    out.add_str("[");
    let mut first: bool = true;
    for i in 0..(*tupdesc).natts {
        let attr = *(*tupdesc).attrs.offset(i as isize);
        let num = (*attr).attnum;
        if (*attr).attisdropped == 1 || num <= 0 {
            continue;
        }
        let col = pg::get_attname(relid, num);
        let typ = pg::format_type_be(pg::get_atttype(relid, num));
        if !first {
            out.add_str(",");
        } else {
            first = false;
        }
        out.add_str("{");
        out.add_json(col);
        out.add_str(":");
        out.add_json(typ);
        out.add_str("}");
    }
    out.add_str("]");
    out.add_str(", ");
    out.add_json("table");
    out.add_str(": ");
    out.add_json(qualified_name);
    out.add_str(" }");
}

extern "C" fn row_to_json(fcinfo: pg::FunctionCallInfo) -> pg::Datum {
    // We wrap the unsafe call to make it safe, so that it can be passed as
    // a function pointer to DirectFunctionCall1Coll(). This is a spurious
    // artifact of the generated binding.
    unsafe { pg::row_to_json(fcinfo) }
}

fn is_stale_toast(datum: pg::Datum) -> bool {
    false
}

// Symbols Postgres needs to find.

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn _PG_init() {}

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn
    _PG_output_plugin_init(cb: *mut pg::OutputPluginCallbacks) {
    init(cb);
}

// Miscellaneous.

const CTRUE: pg::_bool = 1;
const CFALSE: pg::_bool = 0;
<commit_msg>Provide logging macro<commit_after>extern crate libc;
use std::ffi::CString;
use std::mem::size_of;

extern crate rpgffi as pg;

macro_rules! log {
    ($msg:expr) => {
        elog(file!(), line!(), "log()", $msg)
    }
}

// Implementation of initialization and callbacks.

pub unsafe extern "C" fn init(cb: *mut pg::OutputPluginCallbacks) {
    (*cb).startup_cb = Some(startup);
    (*cb).begin_cb = Some(begin);
    (*cb).change_cb = Some(change);
    (*cb).commit_cb = Some(commit);
    (*cb).shutdown_cb = Some(shutdown);
}

unsafe extern "C" fn startup(ctx: *mut pg::Struct_LogicalDecodingContext,
                             options: *mut pg::OutputPluginOptions,
                             _is_init: pg::_bool) {
    use pg::Enum_OutputPluginOutputType::*;
    let last_relid = pg::palloc0(size_of::<pg::Oid>() as u64);
    (*ctx).output_plugin_private = last_relid;
    (*options).output_type = OUTPUT_PLUGIN_TEXTUAL_OUTPUT;
}

unsafe extern "C" fn begin(ctx: *mut pg::Struct_LogicalDecodingContext,
                           txn: *mut pg::ReorderBufferTXN) {
    let s = CString::new("{ \"begin\": %u }").unwrap();
    pg::OutputPluginPrepareWrite(ctx, CTRUE);
    pg::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid);
    pg::OutputPluginWrite(ctx, CTRUE);
}

unsafe extern "C" fn change(ctx: *mut pg::Struct_LogicalDecodingContext,
                            _txn: *mut pg::ReorderBufferTXN,
                            relation: pg::Relation,
                            change: *mut pg::ReorderBufferChange) {
    let relid = (*relation).rd_id;
    let last_relid: *mut pg::Oid =
        (*ctx).output_plugin_private as *mut pg::Oid;
    if *last_relid != relid {
        pg::OutputPluginPrepareWrite(ctx, CFALSE);
        append_schema(relation, (*ctx).out);
        pg::OutputPluginWrite(ctx, CFALSE);
        *last_relid = relid;
    }
    pg::OutputPluginPrepareWrite(ctx, CTRUE);
    append_change(relation, change, (*ctx).out);
    pg::OutputPluginWrite(ctx, CTRUE);
}

unsafe extern "C" fn commit(ctx: *mut pg::Struct_LogicalDecodingContext,
                            txn: *mut pg::ReorderBufferTXN,
                            _lsn: pg::XLogRecPtr) {
    let s = CString::new("{ \"commit\": %u, \"t\": \"%s\" }").unwrap();
    let t = pg::timestamptz_to_str((*txn).commit_time);
    pg::OutputPluginPrepareWrite(ctx, CTRUE);
    pg::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid, t);
    pg::OutputPluginWrite(ctx, CTRUE);
    let last_relid: *mut pg::Oid =
        (*ctx).output_plugin_private as *mut pg::Oid;
    *last_relid = 0;
}

unsafe extern "C" fn shutdown(ctx: *mut pg::Struct_LogicalDecodingContext) {
    pg::pfree((*ctx).output_plugin_private);
}

trait PGAppend<T> {
    unsafe fn add_str(self, T);
    unsafe fn add_json(self, T);
}

impl<'a> PGAppend<&'a str> for pg::StringInfo {
    unsafe fn add_str(self, t: &'a str) {
        pg::appendStringInfoString(self, CString::new(t).unwrap().as_ptr());
    }
    unsafe fn add_json(self, t: &'a str) {
        pg::escape_json(self, CString::new(t).unwrap().as_ptr());
    }
}

impl PGAppend<*mut i8> for pg::StringInfo {
    unsafe fn add_str(self, t: *mut i8) {
        pg::appendStringInfoString(self, t);
    }
    unsafe fn add_json(self, t: *mut i8) {
        pg::escape_json(self, t);
    }
}

unsafe fn append_change(relation: pg::Relation,
                        change: *mut pg::ReorderBufferChange,
                        out: pg::StringInfo) {
    use pg::Enum_ReorderBufferChangeType::*;
    let relid = (*relation).rd_id;
    let name = pg::get_rel_name(relid);
    let ns = pg::get_namespace_name(pg::get_rel_namespace(relid));
    let qualified_name = pg::quote_qualified_identifier(ns, name);
    let tuple_desc = (*relation).rd_att;
    let tuples = (*change).data.tp();
    let tuple_new = (*tuples).newtuple;
    let tuple_old = (*tuples).oldtuple;
    let token = match (*change).action {
        REORDER_BUFFER_CHANGE_INSERT => "insert",
        REORDER_BUFFER_CHANGE_UPDATE => "update",
        REORDER_BUFFER_CHANGE_DELETE => "delete",
        _ => panic!("Unrecognized change action!"),
    };
    out.add_str("{ ");
    out.add_json(token);
    out.add_str(": ");
    append_tuple_buf_as_json(tuple_new, tuple_desc, out);
    if !tuple_old.is_null() {
        out.add_str(", \"@\": ");
        append_tuple_buf_as_json(tuple_old, tuple_desc, out);
    }
    out.add_str(", ");
    out.add_json("table");
    out.add_str(": ");
    out.add_json(qualified_name);
    out.add_str(" }");
}

unsafe fn append_tuple_buf_as_json(data: *mut pg::ReorderBufferTupleBuf,
                                   desc: pg::TupleDesc,
                                   out: pg::StringInfo) {
    if !data.is_null() {
        let heap_tuple = &mut (*data).tuple;
        let n = (*desc).natts as usize;
        let attrs = (*desc).attrs;

        // Pull out every single field to check for stale TOAST.
        let mut datums: Vec<pg::Datum> = Vec::new();
        let mut nulls: Vec<pg::_bool> = Vec::new();
        datums.resize(n, 0);
        nulls.resize(n, CFALSE);
        pg::heap_deform_tuple(heap_tuple,
                              desc,
                              datums.as_mut_ptr(),
                              nulls.as_mut_ptr());

        let mut skip: Vec<pg::Form_pg_attribute> = Vec::with_capacity(n);

        for i in 0..n {
            let datum: pg::Datum = datums[i];
            let attr = *attrs.offset(i as isize);
            if is_stale_toast(datum) && (*attr).attisdropped == CFALSE {
                skip.push(attr);
            }
        }

        // Mark as dropped to trick row_to_json().
        for attr in &mut skip {
            (**attr).attisdropped = CTRUE;
        }

        let datum = pg::heap_copy_tuple_as_datum(heap_tuple, desc);
        let empty_oid: pg::Oid = 0;
        let json =
            pg::DirectFunctionCall1Coll(Some(row_to_json), empty_oid, datum);

        // Set back to true because who knows how else these attrs, which are
        // part of the passed in tuple description, are being used.
        for attr in &mut skip {
            (**attr).attisdropped = CFALSE;
        }

        let ptr = json as *const pg::Struct_varlena;
        let text = pg::text_to_cstring(ptr);
        pg::appendStringInfoString(out, text);
    } else {
        out.add_str("{}");
    }
}

unsafe fn append_schema(relation: pg::Relation, out: pg::StringInfo) {
    let relid = (*relation).rd_id;
    let tupdesc = (*relation).rd_att;
    let name = pg::get_rel_name(relid);
    let ns = pg::get_namespace_name(pg::get_rel_namespace(relid));
    let qualified_name = pg::quote_qualified_identifier(ns, name);
    out.add_str("{ ");
    out.add_json("schema");
    out.add_str(": ");
    out.add_str("[");
    let mut first: bool = true;
    for i in 0..(*tupdesc).natts {
        let attr = *(*tupdesc).attrs.offset(i as isize);
        let num = (*attr).attnum;
        if (*attr).attisdropped == 1 || num <= 0 {
            continue;
        }
        let col = pg::get_attname(relid, num);
        let typ = pg::format_type_be(pg::get_atttype(relid, num));
        if !first {
            out.add_str(",");
        } else {
            first = false;
        }
        out.add_str("{");
        out.add_json(col);
        out.add_str(":");
        out.add_json(typ);
        out.add_str("}");
    }
    out.add_str("]");
    out.add_str(", ");
    out.add_json("table");
    out.add_str(": ");
    out.add_json(qualified_name);
    out.add_str(" }");
}

extern "C" fn row_to_json(fcinfo: pg::FunctionCallInfo) -> pg::Datum {
    // We wrap the unsafe call to make it safe, so that it can be passed as
    // a function pointer to DirectFunctionCall1Coll(). This is a spurious
    // artifact of the generated binding.
    unsafe { pg::row_to_json(fcinfo) }
}

fn is_stale_toast(datum: pg::Datum) -> bool {
    false
}

// Symbols Postgres needs to find.

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn _PG_init() {}

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn
    _PG_output_plugin_init(cb: *mut pg::OutputPluginCallbacks) {
    init(cb);
}

// Miscellaneous.

const CTRUE: pg::_bool = 1;
const CFALSE: pg::_bool = 0;

pub unsafe fn elog(file: &str, line: u32, function: &str, msg: &str) {
    let level = 15;         // The LOG level of logging is normally server-only
    pg::elog_start(CString::new(file).unwrap().as_ptr(),
                   line as ::std::os::raw::c_int,
                   CString::new(function).unwrap().as_ptr());
    pg::elog_finish(level,
                    CString::new("%s").unwrap().as_ptr(),
                    CString::new(msg).unwrap().as_ptr());
}
<|endoftext|>


<commit_before>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;
#[cfg(feature = "cgmath")] extern crate cgmath as cgmath_lib;
#[cfg(feature = "image")] extern crate image as image_lib;

mod ref_into;

#[macro_use] mod macros;
mod context;
mod buffer;
mod shader;
mod program;
mod framebuffer;
mod renderbuffer;
mod texture;
mod texture_units;
mod image_data;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

#[cfg(feature = "cgmath")] mod cgmath_features;
#[cfg(feature = "image")] mod image_features;

pub use gl_lib as gl;
#[cfg(feature = "cgmath")] pub use cgmath_lib as cgmath;
#[cfg(feature = "image")] pub use image_lib as image;

pub use context::*;
pub use buffer::*;
pub use shader::*;
pub use program::*;
pub use framebuffer::*;
pub use renderbuffer::*;
pub use texture::*;
pub use texture_units::*;
pub use image_data::*;
pub use vertex_data::*;
pub use vertex_buffer::*;
pub use index_data::*;
pub use uniform_data::*;
pub use types::*;

pub mod prelude {
    pub use context::{ContextExt, AContext};
    pub use buffer::{BufferBinding, BufferContext,
                     ArrayBufferContext, ElementArrayBufferContext};
    pub use framebuffer::FramebufferContext;
    pub use program::ProgramContext;
    pub use renderbuffer::RenderbufferContext;
    pub use texture_units::TextureUnit;
    pub use texture::TextureBinding;
    pub use vertex_buffer::{VertexBufferContext, IndexBufferContext};
}
<commit_msg>Import `context::ext::*` in the prelude<commit_after>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;
#[cfg(feature = "cgmath")] extern crate cgmath as cgmath_lib;
#[cfg(feature = "image")] extern crate image as image_lib;

mod ref_into;

#[macro_use] mod macros;
mod context;
mod buffer;
mod shader;
mod program;
mod framebuffer;
mod renderbuffer;
mod texture;
mod texture_units;
mod image_data;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

#[cfg(feature = "cgmath")] mod cgmath_features;
#[cfg(feature = "image")] mod image_features;

pub use gl_lib as gl;
#[cfg(feature = "cgmath")] pub use cgmath_lib as cgmath;
#[cfg(feature = "image")] pub use image_lib as image;

pub use context::*;
pub use buffer::*;
pub use shader::*;
pub use program::*;
pub use framebuffer::*;
pub use renderbuffer::*;
pub use texture::*;
pub use texture_units::*;
pub use image_data::*;
pub use vertex_data::*;
pub use vertex_buffer::*;
pub use index_data::*;
pub use uniform_data::*;
pub use types::*;

pub mod prelude {
    pub use context::AContext;
    pub use context::ext::*;
    pub use buffer::{BufferBinding, BufferContext,
                     ArrayBufferContext, ElementArrayBufferContext};
    pub use framebuffer::FramebufferContext;
    pub use program::ProgramContext;
    pub use renderbuffer::RenderbufferContext;
    pub use texture_units::TextureUnit;
    pub use texture::TextureBinding;
    pub use vertex_buffer::{VertexBufferContext, IndexBufferContext};
}
<|endoftext|>


<commit_before>//! Url Encoded middleware for Iron
#![crate_id = "urlencoded"]
#![license = "MIT"]

extern crate url;
extern crate iron;
extern crate serialize;

use iron::{Request, Response, Middleware, Alloy};
use iron::mixin::GetUrl;
use iron::middleware::{Status, Continue, Unwind};

use url::from_str;
use std::collections::HashMap;

#[deriving(Clone)]
struct Encoded(HashMap<String, Vec<String>>);

#[deriving(Clone)]
pub struct UrlEncoded;

impl UrlEncoded {
    pub fn new() -> UrlEncoded {
        UrlEncoded
    }
}

impl Middleware for UrlEncoded {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {

        let raw_url = url::path_from_str(req.url().unwrap().as_slice());

        let query = match raw_url {
            Ok(e) => {
                e.query
            },
            Err(e) => {
                return Continue;
            }
        };

        alloy.insert::<Encoded>(Encoded(vec_to_hashmap(query.clone())));
        Continue
    }
}

fn vec_to_hashmap(q: Vec<(String, String)>) -> HashMap<String, Vec<String>> {
    let mut vec_hashmapped: HashMap<String, Vec<String>> = HashMap::new();

    for (k, v) in q.move_iter() {
        vec_hashmapped.find_with_or_insert_with(
            k, v,
            |_, already, new| {
                already.push(new);
            },
            |_, v| vec![v]
        );
    }
    vec_hashmapped
}
<commit_msg>(feat) Aligned types with new request<commit_after>//! Url Encoded middleware for Iron
#![crate_id = "urlencoded"]
#![license = "MIT"]

extern crate url;
extern crate iron;
extern crate serialize;

use iron::{Request, Response, Middleware, Alloy};
use iron::mixin::GetUrl;
use iron::middleware::{Status, Continue, Unwind};

use url::from_str;
use std::collections::HashMap;

#[deriving(Clone)]
struct Encoded(HashMap<String, Vec<String>>);

#[deriving(Clone)]
pub struct UrlEncoded;

impl UrlEncoded {
    pub fn new() -> UrlEncoded {
        UrlEncoded
    }
}

impl Middleware for UrlEncoded {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {

        let raw_url = req.url();

        let path = match raw_url {
            Some(k) => {
                url::path_from_str(k.as_slice())
            },
            None => {
                return Continue;
            }
        };

        let query = match path {
            Ok(e) => {
                e.query
            },
            Err(e) => {
                return Continue;
            }
        };
        alloy.insert::<Encoded>(Encoded(vec_to_hashmap(query.clone())));
        Continue
    }
}

fn vec_to_hashmap(q: Vec<(String, String)>) -> HashMap<String, Vec<String>> {
    let mut vec_hashmapped: HashMap<String, Vec<String>> = HashMap::new();

    for (k, v) in q.move_iter() {
        vec_hashmapped.find_with_or_insert_with(
            k, v,
            |_, already, new| {
                already.push(new);
            },
            |_, v| vec![v]
        );
    }
    vec_hashmapped
}
<|endoftext|>


<commit_before>#![crate_name = "yaml"]

#![comment = "LibYAML bindings for Rust"]
#![license = "MIT"]
#![crate_type = "lib"]

#![feature(globs)]
#![feature(phase)]
#![feature(struct_variant)]

extern crate libc;

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

use parser::YamlParser;
use constructor::{YamlStandardData, YamlStandardConstructor, YamlConstructor};

pub mod ffi;
pub mod error;
pub mod event;
pub mod parser;
pub mod emitter;
pub mod document;
pub mod codecs;
pub mod constructor;

mod type_size;

pub fn version_string() -> String {
    let c_vsn = unsafe {
        std::c_str::CString::new(ffi::yaml_get_version_string(), false)
    };

    c_vsn.as_str().unwrap().to_string()
}

pub fn version() -> (int, int, int) {
    let mut c_major: libc::c_int = 0;
    let mut c_minor: libc::c_int = 0;
    let mut c_patch: libc::c_int = 0;

    unsafe {
        ffi::yaml_get_version(
            &mut c_major as *mut libc::c_int,
            &mut c_minor as *mut libc::c_int,
            &mut c_patch as *mut libc::c_int
        );
    }

    (c_major as int, c_minor as int, c_patch as int)
}

pub fn parse_bytes_utf8(bytes: &[u8]) -> Result<Vec<YamlStandardData>, String> {
    parse_bytes(bytes, ffi::YamlUtf8Encoding)
}

pub fn parse_bytes(bytes: &[u8], encoding: ffi::YamlEncoding) -> Result<Vec<YamlStandardData>, String> {
    let parser = parser::YamlByteParser::init(bytes, encoding);
    let ctor = YamlStandardConstructor::new();

    parser.load().map(|doc_res| {
        match doc_res {
            Err(e) => Err(e.to_string()),
            Ok(doc) => ctor.construct(doc.root().unwrap())
        }
    }).collect()
}

pub fn parse_io_utf8(reader: &mut Reader) -> Result<Vec<YamlStandardData>, String> {
    parse_io(reader, ffi::YamlUtf8Encoding)
}

pub fn parse_io(reader: &mut Reader, encoding: ffi::YamlEncoding) -> Result<Vec<YamlStandardData>, String> {
    let parser = parser::YamlIoParser::init(reader, encoding);
    let ctor = YamlStandardConstructor::new();

    parser.load().map(|doc_res| {
        match doc_res {
            Err(e) => Err(e.to_string()),
            Ok(doc) => ctor.construct(doc.root().unwrap())
        }
    }).collect()
}

#[cfg(test)]
mod test {
    use std::mem;
    use std::io;
    use constructor::{YamlInteger, YamlSequence};

    #[test]
    fn test_version_string() {
        let vsn = super::version_string();
        assert!("0.1.4".to_string() <= vsn && vsn < "0.2".to_string())
    }

    #[test]
    fn test_version() {
        let vsn = super::version();
        assert!((0, 1, 4) <= vsn && vsn < (0, 2, 0))
    }

    #[test]
    fn test_event_size() {
        assert_eq!(super::type_size::YAML_EVENT_T_SIZE, mem::size_of::<super::ffi::yaml_event_t>())
    }

    #[test]
    fn test_parser_size() {
        assert_eq!(super::type_size::YAML_PARSER_T_SIZE, mem::size_of::<super::ffi::yaml_parser_t>())
    }

    #[test]
    fn test_emitter_size() {
        assert_eq!(super::type_size::YAML_EMITTER_T_SIZE, mem::size_of::<super::ffi::yaml_emitter_t>())
    }

    #[test]
    fn test_document_size() {
        assert_eq!(super::type_size::YAML_DOCUMENT_T_SIZE, mem::size_of::<super::ffi::yaml_document_t>())
    }

    #[test]
    fn test_node_size() {
        assert_eq!(super::type_size::YAML_NODE_T_SIZE, mem::size_of::<super::ffi::yaml_node_t>())
    }

    #[test]
    fn test_parse_bytes() {
        let data = "[1, 2, 3]";
        assert_eq!(Ok(vec![YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])]), super::parse_bytes_utf8(data.as_bytes()))
    }

    #[test]
    fn test_parse_io() {
        let data = "[1, 2, 3]";
        let mut reader = io::BufReader::new(data.as_bytes());
        assert_eq!(Ok(vec![YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])]), super::parse_io_utf8(&mut reader))
    }
}
<commit_msg>Remove struct_variant directive<commit_after>#![crate_name = "yaml"]

#![comment = "LibYAML bindings for Rust"]
#![license = "MIT"]
#![crate_type = "lib"]

#![feature(globs)]
#![feature(phase)]

extern crate libc;

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

use parser::YamlParser;
use constructor::{YamlStandardData, YamlStandardConstructor, YamlConstructor};

pub mod ffi;
pub mod error;
pub mod event;
pub mod parser;
pub mod emitter;
pub mod document;
pub mod codecs;
pub mod constructor;

mod type_size;

pub fn version_string() -> String {
    let c_vsn = unsafe {
        std::c_str::CString::new(ffi::yaml_get_version_string(), false)
    };

    c_vsn.as_str().unwrap().to_string()
}

pub fn version() -> (int, int, int) {
    let mut c_major: libc::c_int = 0;
    let mut c_minor: libc::c_int = 0;
    let mut c_patch: libc::c_int = 0;

    unsafe {
        ffi::yaml_get_version(
            &mut c_major as *mut libc::c_int,
            &mut c_minor as *mut libc::c_int,
            &mut c_patch as *mut libc::c_int
        );
    }

    (c_major as int, c_minor as int, c_patch as int)
}

pub fn parse_bytes_utf8(bytes: &[u8]) -> Result<Vec<YamlStandardData>, String> {
    parse_bytes(bytes, ffi::YamlUtf8Encoding)
}

pub fn parse_bytes(bytes: &[u8], encoding: ffi::YamlEncoding) -> Result<Vec<YamlStandardData>, String> {
    let parser = parser::YamlByteParser::init(bytes, encoding);
    let ctor = YamlStandardConstructor::new();

    parser.load().map(|doc_res| {
        match doc_res {
            Err(e) => Err(e.to_string()),
            Ok(doc) => ctor.construct(doc.root().unwrap())
        }
    }).collect()
}

pub fn parse_io_utf8(reader: &mut Reader) -> Result<Vec<YamlStandardData>, String> {
    parse_io(reader, ffi::YamlUtf8Encoding)
}

pub fn parse_io(reader: &mut Reader, encoding: ffi::YamlEncoding) -> Result<Vec<YamlStandardData>, String> {
    let parser = parser::YamlIoParser::init(reader, encoding);
    let ctor = YamlStandardConstructor::new();

    parser.load().map(|doc_res| {
        match doc_res {
            Err(e) => Err(e.to_string()),
            Ok(doc) => ctor.construct(doc.root().unwrap())
        }
    }).collect()
}

#[cfg(test)]
mod test {
    use std::mem;
    use std::io;
    use constructor::{YamlInteger, YamlSequence};

    #[test]
    fn test_version_string() {
        let vsn = super::version_string();
        assert!("0.1.4".to_string() <= vsn && vsn < "0.2".to_string())
    }

    #[test]
    fn test_version() {
        let vsn = super::version();
        assert!((0, 1, 4) <= vsn && vsn < (0, 2, 0))
    }

    #[test]
    fn test_event_size() {
        assert_eq!(super::type_size::YAML_EVENT_T_SIZE, mem::size_of::<super::ffi::yaml_event_t>())
    }

    #[test]
    fn test_parser_size() {
        assert_eq!(super::type_size::YAML_PARSER_T_SIZE, mem::size_of::<super::ffi::yaml_parser_t>())
    }

    #[test]
    fn test_emitter_size() {
        assert_eq!(super::type_size::YAML_EMITTER_T_SIZE, mem::size_of::<super::ffi::yaml_emitter_t>())
    }

    #[test]
    fn test_document_size() {
        assert_eq!(super::type_size::YAML_DOCUMENT_T_SIZE, mem::size_of::<super::ffi::yaml_document_t>())
    }

    #[test]
    fn test_node_size() {
        assert_eq!(super::type_size::YAML_NODE_T_SIZE, mem::size_of::<super::ffi::yaml_node_t>())
    }

    #[test]
    fn test_parse_bytes() {
        let data = "[1, 2, 3]";
        assert_eq!(Ok(vec![YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])]), super::parse_bytes_utf8(data.as_bytes()))
    }

    #[test]
    fn test_parse_io() {
        let data = "[1, 2, 3]";
        let mut reader = io::BufReader::new(data.as_bytes());
        assert_eq!(Ok(vec![YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])]), super::parse_io_utf8(&mut reader))
    }
}
<|endoftext|>


<commit_before>#![feature(core, plugin, rand, test, negate_unsigned, convert)]
#![plugin(regex_macros)]
extern crate regex;
extern crate v8;

#[test]
fn up_and_down() {
    with_isolate_and_context(move |_, _| {});
    with_isolate_and_context(move |_, _| {});
}

#[test]
fn lock_and_unlock() {
    with_isolate_and_context(move |isolate, _| {
        assert!(v8::Locker::IsActive());
        assert!(v8::Locker::IsLocked(isolate));
        v8::with_unlocker(isolate, move || {
            assert!(!v8::Locker::IsLocked(isolate));
            v8::with_locker(isolate, move || {
                assert!(v8::Locker::IsLocked(isolate));
            });
            assert!(!v8::Locker::IsLocked(isolate));
        });
        assert!(v8::Locker::IsLocked(isolate));
    });
}

#[test]
fn eq() {
    with_isolate_and_context(move |isolate, _| {
        let a = v8::Object::New(isolate).unwrap();
        let b = v8::Object::New(isolate).unwrap();
        assert_eq!(a, a);
        assert_eq!(b, b);
        assert!(a != b);
    });
}

#[test]
fn show() {
    with_isolate_and_context(move |isolate, _| {
        let val = v8::Number::New(isolate, 13.37).unwrap();
        let re = regex!("Number\\(0x[0-9a-f]+\\)");
        let pp = format!("{}", val);
        assert!(re.is_match(pp.as_str()));
        let val = v8::Object::New(isolate).unwrap();
        let re = regex!("Object\\(0x[0-9a-f]+\\)");
        let pp = format!("{}", val);
        assert!(re.is_match(pp.as_str()));
    });
}

#[test]
fn fortytwo() {
    with_isolate_and_context(move |isolate, _| {
        let source = v8::String::NewFromUtf8(isolate, "42",
                                             v8::NewStringType::kNormalString).unwrap();
        assert!(source.IsString());
        assert!(!source.IsStringObject());
        let script = v8::Script::Compile(source, None).unwrap();
        let result = script.Run().unwrap();
        assert!(!result.IsNull());
        assert!(result.IsNumber());
        assert!(!result.IsUndefined());
    });
}

#[test]
fn primitives() {
    with_isolate_and_context(move |isolate, _| {
        assert!(v8::Null(isolate).IsNull());
        assert!(v8::Undefined(isolate).IsUndefined());
        assert!(v8::True(isolate).IsTrue());
        assert!(v8::False(isolate).IsFalse());
        assert!(v8::String::Empty(isolate).IsString());
        assert!(v8::String::Empty(isolate).Length() == 0);
    });
}

#[test]
fn booleans() {
    with_isolate_and_context(move |isolate, _| {
        assert!(v8::Boolean::New(isolate, true).unwrap().IsTrue());
        assert!(v8::Boolean::New(isolate, false).unwrap().IsFalse());
        assert!(v8::Boolean::New(isolate, true).unwrap().Value());
        assert!(!v8::Boolean::New(isolate, false).unwrap().Value());
    });
}

#[test]
fn integers() {
    with_isolate_and_context(move |isolate, _| {
        assert_eq!(42, v8::Integer::New(isolate, 42).unwrap().Value());
        assert_eq!(-1 as u32 as i64,
                   v8::Integer::NewFromUnsigned(isolate, -1).unwrap().Value());
        assert_eq!(-1, v8::Int32::New(isolate, -1).unwrap().Value());
        assert_eq!(-1 as u32, v8::Uint32::New(isolate, -1).unwrap().Value());
    });
}

#[test]
fn basic_number() {
    with_isolate_and_context(move |isolate, _| {
        let val = 13.37;
        let num = v8::Number::New(isolate, val).unwrap();
        assert_eq!(val, num.NumberValue());
    });
}

#[test]
fn basic_object() {
    with_isolate_and_context(move |isolate, _| {
        let object = v8::Object::New(isolate).unwrap();
        assert!(object.IsObject());
        let key = v8::String::NewFromUtf8(isolate, "the_key",
                                          v8::NewStringType::kNormalString).unwrap();
        let value = v8::String::NewFromUtf8(isolate, "the_value",
                                            v8::NewStringType::kNormalString).unwrap();
        assert!(object.Set(key, value));
        assert!(object.Get(key).unwrap().IsString());
    });
}

#[test]
fn object_get_and_set() {
    with_isolate_and_context(move |isolate, _| {
        let obj = v8::Object::New(isolate).unwrap();
        let idx = 123 as u32;
        let key = v8::String::NewFromUtf8(isolate, "the_key",
                                          v8::NewStringType::kNormalString).unwrap();
        let abc = v8::Object::New(isolate).unwrap();
        let def = v8::Object::New(isolate).unwrap();
        assert!(obj.Set(idx, abc));
        assert!(obj.Set(key, def));
        assert_eq!(obj.Get(idx).unwrap(), abc.As());
        assert_eq!(obj.Get(key).unwrap(), def.As());
    });
}

#[test]
fn global_object() {
    with_isolate_and_context(move |isolate, context| {
        let key = v8::String::NewFromUtf8(isolate, "Object",
                                          v8::NewStringType::kNormalString).unwrap();
        assert!(context.Global().unwrap().Get(key).unwrap().IsObject());
    });
}

#[test]
fn native_api_call() {
    with_isolate_and_context(move |isolate, context| {
        extern fn f(info: v8::FunctionCallbackInfo) {
            let isolate = info.GetIsolate();
            let mut return_value = info.GetReturnValue();
            assert_eq!(isolate, return_value.GetIsolate());
            assert!(info.At(0).IsNumber());
            assert!(info.At(1).IsNumber());
            let a = info.At(0).NumberValue();
            let b = info.At(1).NumberValue();
            let x = v8::Number::New(isolate, a * b).unwrap();
            return_value.Set(x);
        }
        let t = v8::FunctionTemplate::New(isolate, Some(f),
                                          None, None, 2).unwrap();
        let key = v8::String::NewFromUtf8(isolate, "f",
                                          v8::NewStringType::kNormalString).unwrap();
        let global = context.Global().unwrap();
        global.Set(key, t.GetFunction().unwrap());
        assert!(global.Get(key).unwrap().IsFunction());
        let result = eval(isolate, "f(1337, 42)").unwrap();
        assert!(result.IsNumber());
        assert_eq!(result.NumberValue(), 1337. * 42.);
    });
}

#[test]
fn return_values() {
    with_isolate_and_context(move |isolate, context| {
        extern fn f(info: v8::FunctionCallbackInfo) {
            match info.At(0).NumberValue() {
                0. => info.GetReturnValue().SetEmptyString(),
                1. => info.GetReturnValue().SetNull(),
                _ => info.GetReturnValue().SetUndefined(),
            }
        }
        let t = v8::FunctionTemplate::New(isolate, Some(f),
                                          None, None, 1).unwrap();
        let key = v8::String::NewFromUtf8(isolate, "f",
                                          v8::NewStringType::kNormalString).unwrap();
        context.Global().unwrap().Set(key, t.GetFunction().unwrap());
        assert!(eval(isolate, "f(0)").unwrap().IsString());
        assert!(eval(isolate, "f(1)").unwrap().IsNull());
        assert!(eval(isolate, "f(2)").unwrap().IsUndefined());
    });
}

#[test]
fn function_call() {
    with_isolate_and_context(move |isolate, _| {
        let val = eval(isolate, "(function(x, y) { return x * y })").unwrap();
        let fun: v8::Function = val.As();
        let argv = [v8::Int32::New(isolate, 42).unwrap().As(),
                    v8::Int32::New(isolate, 1337).unwrap().As()];
        let result = fun.Call(v8::Null(isolate), &argv).unwrap();
        assert!(result.IsNumber());
        assert!(result.NumberValue() == 42. * 1337.);
        assert!(result.IntegerValue() == 42 * 1337);
        assert!(result.IsUint32());
        assert!(result.Uint32Value() == 42 * 1337);
        assert!(result.IsInt32());
        assert!(result.Int32Value() == 42 * 1337);
    });
}

fn eval(isolate: v8::Isolate, raw_source: &str) -> Option<v8::Value> {
    let source = v8::String::NewFromUtf8(isolate, raw_source,
                                         v8::NewStringType::kNormalString).unwrap();
    let script = v8::Script::Compile(source, None).unwrap();
    script.Run()
}

fn with_isolate_and_context<F>(closure: F) where F: Fn(v8::Isolate, v8::Context) {
    assert!(v8::V8::Initialize());
    {
        let mut isolate = v8::Isolate::New(None).unwrap();
        v8::with_locker(isolate, move || {
            v8::with_handle_scope(isolate, move || {
                v8::with_isolate_scope(isolate, move || {
                    let context = v8::Context::New(isolate).unwrap();
                    v8::with_context_scope(context, move || {
                        closure(isolate, context)
                    });
                });
            });
        });
        isolate.Dispose();
    }
    // Don't call v8::V8::Dispose(), it permanently tears down V8.
}
<commit_msg>Remove some unused feature flags<commit_after>#![feature(plugin, negate_unsigned, convert)]
#![plugin(regex_macros)]
extern crate regex;
extern crate v8;

#[test]
fn up_and_down() {
    with_isolate_and_context(move |_, _| {});
    with_isolate_and_context(move |_, _| {});
}

#[test]
fn lock_and_unlock() {
    with_isolate_and_context(move |isolate, _| {
        assert!(v8::Locker::IsActive());
        assert!(v8::Locker::IsLocked(isolate));
        v8::with_unlocker(isolate, move || {
            assert!(!v8::Locker::IsLocked(isolate));
            v8::with_locker(isolate, move || {
                assert!(v8::Locker::IsLocked(isolate));
            });
            assert!(!v8::Locker::IsLocked(isolate));
        });
        assert!(v8::Locker::IsLocked(isolate));
    });
}

#[test]
fn eq() {
    with_isolate_and_context(move |isolate, _| {
        let a = v8::Object::New(isolate).unwrap();
        let b = v8::Object::New(isolate).unwrap();
        assert_eq!(a, a);
        assert_eq!(b, b);
        assert!(a != b);
    });
}

#[test]
fn show() {
    with_isolate_and_context(move |isolate, _| {
        let val = v8::Number::New(isolate, 13.37).unwrap();
        let re = regex!("Number\\(0x[0-9a-f]+\\)");
        let pp = format!("{}", val);
        assert!(re.is_match(pp.as_str()));
        let val = v8::Object::New(isolate).unwrap();
        let re = regex!("Object\\(0x[0-9a-f]+\\)");
        let pp = format!("{}", val);
        assert!(re.is_match(pp.as_str()));
    });
}

#[test]
fn fortytwo() {
    with_isolate_and_context(move |isolate, _| {
        let source = v8::String::NewFromUtf8(isolate, "42",
                                             v8::NewStringType::kNormalString).unwrap();
        assert!(source.IsString());
        assert!(!source.IsStringObject());
        let script = v8::Script::Compile(source, None).unwrap();
        let result = script.Run().unwrap();
        assert!(!result.IsNull());
        assert!(result.IsNumber());
        assert!(!result.IsUndefined());
    });
}

#[test]
fn primitives() {
    with_isolate_and_context(move |isolate, _| {
        assert!(v8::Null(isolate).IsNull());
        assert!(v8::Undefined(isolate).IsUndefined());
        assert!(v8::True(isolate).IsTrue());
        assert!(v8::False(isolate).IsFalse());
        assert!(v8::String::Empty(isolate).IsString());
        assert!(v8::String::Empty(isolate).Length() == 0);
    });
}

#[test]
fn booleans() {
    with_isolate_and_context(move |isolate, _| {
        assert!(v8::Boolean::New(isolate, true).unwrap().IsTrue());
        assert!(v8::Boolean::New(isolate, false).unwrap().IsFalse());
        assert!(v8::Boolean::New(isolate, true).unwrap().Value());
        assert!(!v8::Boolean::New(isolate, false).unwrap().Value());
    });
}

#[test]
fn integers() {
    with_isolate_and_context(move |isolate, _| {
        assert_eq!(42, v8::Integer::New(isolate, 42).unwrap().Value());
        assert_eq!(-1 as u32 as i64,
                   v8::Integer::NewFromUnsigned(isolate, -1).unwrap().Value());
        assert_eq!(-1, v8::Int32::New(isolate, -1).unwrap().Value());
        assert_eq!(-1 as u32, v8::Uint32::New(isolate, -1).unwrap().Value());
    });
}

#[test]
fn basic_number() {
    with_isolate_and_context(move |isolate, _| {
        let val = 13.37;
        let num = v8::Number::New(isolate, val).unwrap();
        assert_eq!(val, num.NumberValue());
    });
}

#[test]
fn basic_object() {
    with_isolate_and_context(move |isolate, _| {
        let object = v8::Object::New(isolate).unwrap();
        assert!(object.IsObject());
        let key = v8::String::NewFromUtf8(isolate, "the_key",
                                          v8::NewStringType::kNormalString).unwrap();
        let value = v8::String::NewFromUtf8(isolate, "the_value",
                                            v8::NewStringType::kNormalString).unwrap();
        assert!(object.Set(key, value));
        assert!(object.Get(key).unwrap().IsString());
    });
}

#[test]
fn object_get_and_set() {
    with_isolate_and_context(move |isolate, _| {
        let obj = v8::Object::New(isolate).unwrap();
        let idx = 123 as u32;
        let key = v8::String::NewFromUtf8(isolate, "the_key",
                                          v8::NewStringType::kNormalString).unwrap();
        let abc = v8::Object::New(isolate).unwrap();
        let def = v8::Object::New(isolate).unwrap();
        assert!(obj.Set(idx, abc));
        assert!(obj.Set(key, def));
        assert_eq!(obj.Get(idx).unwrap(), abc.As());
        assert_eq!(obj.Get(key).unwrap(), def.As());
    });
}

#[test]
fn global_object() {
    with_isolate_and_context(move |isolate, context| {
        let key = v8::String::NewFromUtf8(isolate, "Object",
                                          v8::NewStringType::kNormalString).unwrap();
        assert!(context.Global().unwrap().Get(key).unwrap().IsObject());
    });
}

#[test]
fn native_api_call() {
    with_isolate_and_context(move |isolate, context| {
        extern fn f(info: v8::FunctionCallbackInfo) {
            let isolate = info.GetIsolate();
            let mut return_value = info.GetReturnValue();
            assert_eq!(isolate, return_value.GetIsolate());
            assert!(info.At(0).IsNumber());
            assert!(info.At(1).IsNumber());
            let a = info.At(0).NumberValue();
            let b = info.At(1).NumberValue();
            let x = v8::Number::New(isolate, a * b).unwrap();
            return_value.Set(x);
        }
        let t = v8::FunctionTemplate::New(isolate, Some(f),
                                          None, None, 2).unwrap();
        let key = v8::String::NewFromUtf8(isolate, "f",
                                          v8::NewStringType::kNormalString).unwrap();
        let global = context.Global().unwrap();
        global.Set(key, t.GetFunction().unwrap());
        assert!(global.Get(key).unwrap().IsFunction());
        let result = eval(isolate, "f(1337, 42)").unwrap();
        assert!(result.IsNumber());
        assert_eq!(result.NumberValue(), 1337. * 42.);
    });
}

#[test]
fn return_values() {
    with_isolate_and_context(move |isolate, context| {
        extern fn f(info: v8::FunctionCallbackInfo) {
            match info.At(0).NumberValue() {
                0. => info.GetReturnValue().SetEmptyString(),
                1. => info.GetReturnValue().SetNull(),
                _ => info.GetReturnValue().SetUndefined(),
            }
        }
        let t = v8::FunctionTemplate::New(isolate, Some(f),
                                          None, None, 1).unwrap();
        let key = v8::String::NewFromUtf8(isolate, "f",
                                          v8::NewStringType::kNormalString).unwrap();
        context.Global().unwrap().Set(key, t.GetFunction().unwrap());
        assert!(eval(isolate, "f(0)").unwrap().IsString());
        assert!(eval(isolate, "f(1)").unwrap().IsNull());
        assert!(eval(isolate, "f(2)").unwrap().IsUndefined());
    });
}

#[test]
fn function_call() {
    with_isolate_and_context(move |isolate, _| {
        let val = eval(isolate, "(function(x, y) { return x * y })").unwrap();
        let fun: v8::Function = val.As();
        let argv = [v8::Int32::New(isolate, 42).unwrap().As(),
                    v8::Int32::New(isolate, 1337).unwrap().As()];
        let result = fun.Call(v8::Null(isolate), &argv).unwrap();
        assert!(result.IsNumber());
        assert!(result.NumberValue() == 42. * 1337.);
        assert!(result.IntegerValue() == 42 * 1337);
        assert!(result.IsUint32());
        assert!(result.Uint32Value() == 42 * 1337);
        assert!(result.IsInt32());
        assert!(result.Int32Value() == 42 * 1337);
    });
}

fn eval(isolate: v8::Isolate, raw_source: &str) -> Option<v8::Value> {
    let source = v8::String::NewFromUtf8(isolate, raw_source,
                                         v8::NewStringType::kNormalString).unwrap();
    let script = v8::Script::Compile(source, None).unwrap();
    script.Run()
}

fn with_isolate_and_context<F>(closure: F) where F: Fn(v8::Isolate, v8::Context) {
    assert!(v8::V8::Initialize());
    {
        let mut isolate = v8::Isolate::New(None).unwrap();
        v8::with_locker(isolate, move || {
            v8::with_handle_scope(isolate, move || {
                v8::with_isolate_scope(isolate, move || {
                    let context = v8::Context::New(isolate).unwrap();
                    v8::with_context_scope(context, move || {
                        closure(isolate, context)
                    });
                });
            });
        });
        isolate.Dispose();
    }
    // Don't call v8::V8::Dispose(), it permanently tears down V8.
}
<|endoftext|>


<commit_before>
use gfx;
use gfx::DeviceHelper;
use graphics::{ Context, BackEnd };
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;

use Texture;

static VERTEX_SHADER: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
varying vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
out vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
varying vec4 v_Color;
void main() {
    gl_FragColor = v_Color;
}
"
    GLSL_150: b"
#version 150 core
in vec4 v_Color;
out vec4 o_Color;
void main() {
    o_Color = v_Color;
}
"
};

static VERTEX_SHADER_UV: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
attribute vec2 uv;
uniform sampler2D s_texture;
varying vec4 v_Color;
varying vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
in vec2 uv;
uniform sampler2D s_texture;
out vec4 v_Color;
out vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER_UV: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
varying vec2 v_UV;
varying vec4 v_Color;
void main()
{
    gl_FragColor = texture2D(s_texture, v_UV) * v_Color;
}
"
    GLSL_150: b"
#version 150 core
out vec4 o_Color;
uniform sampler2D s_texture;
in vec2 v_UV;
in vec4 v_Color;
void main()
{
    o_Color = texture(s_texture, v_UV) * v_Color;
}
"
};

static POS_COMPONENTS: uint = 2;
static COLOR_COMPONENTS: uint = 4;
static UV_COMPONENTS: uint = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

#[vertex_format]
struct PositionFormat { pos: [f32, ..2] }

#[vertex_format]
struct ColorFormat { color: [f32, ..4] }

#[vertex_format]
struct TexCoordsFormat { uv: [f32, ..2] }

#[allow(unused_imports)]
#[shader_param(BatchUV, OwnedBatchUV)]
struct ParamsUV {
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct G2D {
    buffer_pos: gfx::BufferHandle<f32>,
    buffer_color: gfx::BufferHandle<f32>,
    buffer_uv: gfx::BufferHandle<f32>,
    batch: gfx::batch::OwnedBatch<(), ()>,
    batch_uv: OwnedBatchUV,
}

impl G2D {
    /// Creates a new G2D object.
    pub fn new<D: gfx::Device<C>,
               C: gfx::CommandBuffer>(device: &mut D) -> G2D {
        let program = device.link_program(
                VERTEX_SHADER.clone(),
                FRAGMENT_SHADER.clone()
            ).unwrap();
        let program_uv = device.link_program(
                VERTEX_SHADER_UV.clone(),
                FRAGMENT_SHADER_UV.clone()
            ).unwrap();

        let buffer_pos = device.create_buffer(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_color = device.create_buffer(
            COLOR_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_uv = device.create_buffer(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);

        let mut mesh = gfx::Mesh::new(BUFFER_SIZE as u32);
        mesh.attributes.extend(gfx::VertexFormat::generate(
            None::<PositionFormat>,
            buffer_pos.raw()
        ).into_iter());
        mesh.attributes.extend(gfx::VertexFormat::generate(
            None::<ColorFormat>,
            buffer_color.raw()
        ).into_iter());

        // Reuse parameters from `mesh`.
        let mut mesh_uv = mesh.clone();
        mesh_uv.attributes.extend(gfx::VertexFormat::generate(
            None::<TexCoordsFormat>,
            buffer_uv.raw()
        ).into_iter());

        let mut batch = gfx::batch::OwnedBatch::new(mesh, program, ()).unwrap();

        let sampler = device.create_sampler(
                gfx::tex::SamplerInfo::new(gfx::tex::Trilinear,
                                           gfx::tex::Clamp)
            );

        // Create a dummy texture
        let texture_info = gfx::tex::TextureInfo {
            width: 1,
            height: 1,
            depth: 1,
            levels: 1,
            kind: gfx::tex::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
                [0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
            .unwrap();
        let params_uv = ParamsUV {
            s_texture: (texture, Some(sampler))
        };

        let mut batch_uv = gfx::batch::OwnedBatch::new(
            mesh_uv, program_uv, params_uv).unwrap();

        // Disable culling.
        batch.state.primitive.method =
            gfx::state::Fill(gfx::state::CullMode::Nothing);
        batch_uv.state.primitive.method =
            gfx::state::Fill(gfx::state::CullMode::Nothing);

        G2D {
            buffer_pos: buffer_pos,
            buffer_color: buffer_color,
            buffer_uv: buffer_uv,
            batch: batch,
            batch_uv: batch_uv,
        }
    }

    /// Renders graphics to a Gfx renderer.
    pub fn draw<C: gfx::CommandBuffer>(
        &mut self,
        renderer: &mut gfx::Renderer<C>,
        frame: &gfx::Frame,
        f: |c: Context, g: &mut GraphicsBackEnd<C>|
    ) {
        let ref mut g = GraphicsBackEnd::new(
            renderer,
            frame,
            self
        );
        let c = Context::abs(
            frame.width as f64,
            frame.height as f64
        );
        f(c, g);
    }
}

/// Used for rendering 2D graphics.
pub struct GraphicsBackEnd<'a, C: 'a + gfx::CommandBuffer> {
    renderer: &'a mut gfx::Renderer<C>,
    frame: &'a gfx::Frame,
    g2d: &'a mut G2D,
}

impl<'a, C: gfx::CommandBuffer> GraphicsBackEnd<'a, C> {
    /// Creates a new object for rendering 2D graphics.
    pub fn new(renderer: &'a mut gfx::Renderer<C>,
               frame: &'a gfx::Frame,
               g2d: &'a mut G2D) -> GraphicsBackEnd<'a, C> {
        GraphicsBackEnd {
            renderer: renderer,
            frame: frame,
            g2d: g2d,
        }
    }
}

impl<'a, C: gfx::CommandBuffer> BackEnd<Texture>
for GraphicsBackEnd<'a, C> {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        let &GraphicsBackEnd {
            ref mut renderer,
            frame,
            ..
        } = self;
        renderer.clear(
                gfx::ClearData {
                    color: [r, g, b, a],
                    depth: 0.0,
                    stencil: 0,
                },
                gfx::COLOR,
                frame
            );
    }

    fn enable_alpha_blend(&mut self) {
        use std::default::Default;
        use gfx::state::{Normal, Inverse, Factor};

        let blend = gfx::state::Blend {
            value: [1.0, 1.0, 1.0, 1.0],
            color: gfx::state::BlendChannel {
                    equation: gfx::state::FuncAdd,
                    source: Factor(Normal, gfx::state::SourceAlpha),
                    destination: Factor(Inverse, gfx::state::SourceAlpha)
                },
            alpha: Default::default()
        };

        self.g2d.batch.state.blend = Some(blend);
        self.g2d.batch_uv.state.blend = Some(blend);
    }

    fn disable_alpha_blend(&mut self) {
        self.g2d.batch.state.blend = None;
        self.g2d.batch_uv.state.blend = None;
    }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        let &GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &G2D {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut batch,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch.slice = gfx::Slice {
                prim_type: gfx::TriangleList,
                start: 0,
                end: n as u32,
                kind: gfx::SliceKind::Vertex
            };
        renderer.draw(batch, *frame);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let ParamsUV {
            s_texture: (ref mut s_texture, _)
        } = self.g2d.batch_uv.param;
        *s_texture = texture.handle;
    }

    fn disable_single_texture(&mut self) {}

    fn has_texture_alpha(&self, texture: &Texture) -> bool {
        texture.handle.get_info().format.get_components() == Some(gfx::tex::RGBA)
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        let &GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &G2D {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut buffer_uv,
                ref mut batch_uv,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        assert_eq!(
            vertices.len() * UV_COMPONENTS,
            texture_coords.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);
        renderer.update_buffer_vec(*buffer_uv, texture_coords, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch_uv.slice = gfx::Slice {
                prim_type: gfx::TriangleList,
                start: 0,
                end: n as u32,
                kind: gfx::SliceKind::Vertex
            };
        renderer.draw(batch_uv, *frame);
    }
}
<commit_msg>Updating for rust-nightly. [] => &[]<commit_after>
use gfx;
use gfx::DeviceHelper;
use graphics::{ Context, BackEnd };
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;

use Texture;

static VERTEX_SHADER: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
varying vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
out vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
varying vec4 v_Color;
void main() {
    gl_FragColor = v_Color;
}
"
    GLSL_150: b"
#version 150 core
in vec4 v_Color;
out vec4 o_Color;
void main() {
    o_Color = v_Color;
}
"
};

static VERTEX_SHADER_UV: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
attribute vec2 uv;
uniform sampler2D s_texture;
varying vec4 v_Color;
varying vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
in vec2 uv;
uniform sampler2D s_texture;
out vec4 v_Color;
out vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER_UV: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
varying vec2 v_UV;
varying vec4 v_Color;
void main()
{
    gl_FragColor = texture2D(s_texture, v_UV) * v_Color;
}
"
    GLSL_150: b"
#version 150 core
out vec4 o_Color;
uniform sampler2D s_texture;
in vec2 v_UV;
in vec4 v_Color;
void main()
{
    o_Color = texture(s_texture, v_UV) * v_Color;
}
"
};

static POS_COMPONENTS: uint = 2;
static COLOR_COMPONENTS: uint = 4;
static UV_COMPONENTS: uint = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

#[vertex_format]
struct PositionFormat { pos: [f32, ..2] }

#[vertex_format]
struct ColorFormat { color: [f32, ..4] }

#[vertex_format]
struct TexCoordsFormat { uv: [f32, ..2] }

#[allow(unused_imports)]
#[shader_param(BatchUV, OwnedBatchUV)]
struct ParamsUV {
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct G2D {
    buffer_pos: gfx::BufferHandle<f32>,
    buffer_color: gfx::BufferHandle<f32>,
    buffer_uv: gfx::BufferHandle<f32>,
    batch: gfx::batch::OwnedBatch<(), ()>,
    batch_uv: OwnedBatchUV,
}

impl G2D {
    /// Creates a new G2D object.
    pub fn new<D: gfx::Device<C>,
               C: gfx::CommandBuffer>(device: &mut D) -> G2D {
        let program = device.link_program(
                VERTEX_SHADER.clone(),
                FRAGMENT_SHADER.clone()
            ).unwrap();
        let program_uv = device.link_program(
                VERTEX_SHADER_UV.clone(),
                FRAGMENT_SHADER_UV.clone()
            ).unwrap();

        let buffer_pos = device.create_buffer(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_color = device.create_buffer(
            COLOR_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_uv = device.create_buffer(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);

        let mut mesh = gfx::Mesh::new(BUFFER_SIZE as u32);
        mesh.attributes.extend(gfx::VertexFormat::generate(
            None::<PositionFormat>,
            buffer_pos.raw()
        ).into_iter());
        mesh.attributes.extend(gfx::VertexFormat::generate(
            None::<ColorFormat>,
            buffer_color.raw()
        ).into_iter());

        // Reuse parameters from `mesh`.
        let mut mesh_uv = mesh.clone();
        mesh_uv.attributes.extend(gfx::VertexFormat::generate(
            None::<TexCoordsFormat>,
            buffer_uv.raw()
        ).into_iter());

        let mut batch = gfx::batch::OwnedBatch::new(mesh, program, ()).unwrap();

        let sampler = device.create_sampler(
                gfx::tex::SamplerInfo::new(gfx::tex::Trilinear,
                                           gfx::tex::Clamp)
            );

        // Create a dummy texture
        let texture_info = gfx::tex::TextureInfo {
            width: 1,
            height: 1,
            depth: 1,
            levels: 1,
            kind: gfx::tex::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
                &[0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
            .unwrap();
        let params_uv = ParamsUV {
            s_texture: (texture, Some(sampler))
        };

        let mut batch_uv = gfx::batch::OwnedBatch::new(
            mesh_uv, program_uv, params_uv).unwrap();

        // Disable culling.
        batch.state.primitive.method =
            gfx::state::Fill(gfx::state::CullMode::Nothing);
        batch_uv.state.primitive.method =
            gfx::state::Fill(gfx::state::CullMode::Nothing);

        G2D {
            buffer_pos: buffer_pos,
            buffer_color: buffer_color,
            buffer_uv: buffer_uv,
            batch: batch,
            batch_uv: batch_uv,
        }
    }

    /// Renders graphics to a Gfx renderer.
    pub fn draw<C: gfx::CommandBuffer>(
        &mut self,
        renderer: &mut gfx::Renderer<C>,
        frame: &gfx::Frame,
        f: |c: Context, g: &mut GraphicsBackEnd<C>|
    ) {
        let ref mut g = GraphicsBackEnd::new(
            renderer,
            frame,
            self
        );
        let c = Context::abs(
            frame.width as f64,
            frame.height as f64
        );
        f(c, g);
    }
}

/// Used for rendering 2D graphics.
pub struct GraphicsBackEnd<'a, C: 'a + gfx::CommandBuffer> {
    renderer: &'a mut gfx::Renderer<C>,
    frame: &'a gfx::Frame,
    g2d: &'a mut G2D,
}

impl<'a, C: gfx::CommandBuffer> GraphicsBackEnd<'a, C> {
    /// Creates a new object for rendering 2D graphics.
    pub fn new(renderer: &'a mut gfx::Renderer<C>,
               frame: &'a gfx::Frame,
               g2d: &'a mut G2D) -> GraphicsBackEnd<'a, C> {
        GraphicsBackEnd {
            renderer: renderer,
            frame: frame,
            g2d: g2d,
        }
    }
}

impl<'a, C: gfx::CommandBuffer> BackEnd<Texture>
for GraphicsBackEnd<'a, C> {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        let &GraphicsBackEnd {
            ref mut renderer,
            frame,
            ..
        } = self;
        renderer.clear(
                gfx::ClearData {
                    color: [r, g, b, a],
                    depth: 0.0,
                    stencil: 0,
                },
                gfx::COLOR,
                frame
            );
    }

    fn enable_alpha_blend(&mut self) {
        use std::default::Default;
        use gfx::state::{Normal, Inverse, Factor};

        let blend = gfx::state::Blend {
            value: [1.0, 1.0, 1.0, 1.0],
            color: gfx::state::BlendChannel {
                    equation: gfx::state::FuncAdd,
                    source: Factor(Normal, gfx::state::SourceAlpha),
                    destination: Factor(Inverse, gfx::state::SourceAlpha)
                },
            alpha: Default::default()
        };

        self.g2d.batch.state.blend = Some(blend);
        self.g2d.batch_uv.state.blend = Some(blend);
    }

    fn disable_alpha_blend(&mut self) {
        self.g2d.batch.state.blend = None;
        self.g2d.batch_uv.state.blend = None;
    }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        let &GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &G2D {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut batch,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch.slice = gfx::Slice {
                prim_type: gfx::TriangleList,
                start: 0,
                end: n as u32,
                kind: gfx::SliceKind::Vertex
            };
        renderer.draw(batch, *frame);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let ParamsUV {
            s_texture: (ref mut s_texture, _)
        } = self.g2d.batch_uv.param;
        *s_texture = texture.handle;
    }

    fn disable_single_texture(&mut self) {}

    fn has_texture_alpha(&self, texture: &Texture) -> bool {
        texture.handle.get_info().format.get_components() == Some(gfx::tex::RGBA)
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        let &GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &G2D {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut buffer_uv,
                ref mut batch_uv,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        assert_eq!(
            vertices.len() * UV_COMPONENTS,
            texture_coords.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);
        renderer.update_buffer_vec(*buffer_uv, texture_coords, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch_uv.slice = gfx::Slice {
                prim_type: gfx::TriangleList,
                start: 0,
                end: n as u32,
                kind: gfx::SliceKind::Vertex
            };
        renderer.draw(batch_uv, *frame);
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Add};
use std::slice::Iter;

pub trait Interpolate {
    fn interpolate(&self, other: &Self, t: f32) -> Self;
}

impl<T: Mul<f32, Output = T> + Add<Output = T> + Copy> Interpolate for T {
    fn interpolate(&self, other: &Self, t: f32) -> Self {
        *self * (1.0 - t) + *other * t
    }
}

/// Structure for computing the B-spline with the given control points
/// and knots.
pub struct BSpline<T: Interpolate + Copy> {
    /// Degree of the polynomial that we use to make the curve segments
    degree: usize,
    /// Control points for the curve
    control_points: Vec<T>,
    /// TODO: What is a good description for the knots?
    knots: Vec<f32>,
}

impl<T: Interpolate + Copy> BSpline<T> {
    /// Create a new B-spline curve of the desired degree that will blend between
    /// the passed control points using the knots. The knots should be sorted in ascending
    /// order, otherwise they will be sorted for you which may lead to undesired knots
    /// for control points
    pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<f32>) -> BSpline<T> {
        // TODO: Maybe a ctor for cardinal curves that will check we have the right number of
        // knots? Is this check correct?
        if control_points.len() < degree {
            panic!("Too few control points for curve");
        }
        if knots.len() != control_points.len() + degree + 1 {
            panic!(format!("Invalid number of knots, got {}, expected {}", knots.len(),
                control_points.len() + degree + 1));
        }
        knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
        BSpline { degree: degree, control_points: control_points, knots: knots }
    }
    /// Compute a point on the curve at `t`
    /// TODO: Handling of out of bounds t values? Are t values not in the domain considered
    /// out of range? The extra `degree` values are just for when we're going down the tree
    /// to find the interpolated values there right?
    pub fn point(&self, t: f32) -> T {
        // Find the first index with a knot value greater than the t we're searching for. We want
        // to find i such that: knot[i] <= t < knot[i + 1]
        let i = match upper_bounds(&self.knots[..], t) {
            Some(x) if x == 0 => self.degree,
            Some(x) => x,
            None => self.knots.len() - self.degree - 1,
        };
        self.de_boors(t, self.degree, i)
    }
    /// Get an iterator over the control points
    pub fn control_points(&self) -> Iter<T> {
        self.control_points.iter()
    }
    /// Get an iterator over the knots
    pub fn knots(&self) -> Iter<f32> {
        self.knots.iter()
    }
    /// Recursively compute de Boor's B-spline algorithm. TODO: This is terrible,
    /// compute it iteratively! Recursive version is just for a simple formualation
    /// of the initial implementation. Could we do memo-ization? If we switch to an
    /// iterative one and recursively compute the weights our interpolation at
    /// each level is no longer linear, which makes it harder to support things like
    /// Quaternions.
    fn de_boors(&self, t: f32, k: usize, i: usize) -> T {
        if k == 0 {
            self.control_points[i - 1]
        } else {
            let alpha = (t - self.knots[i - 1]) / (self.knots[i + self.degree - k] - self.knots[i - 1]);
            self.de_boors(t, k - 1, i - 1).interpolate(&self.de_boors(t, k - 1, i), alpha)
        }
    }
}

/// Return the index of the first element greater than the value passed.
/// The data **must** be sorted.
/// If no element greater than the value passed is found the function returns None.
fn upper_bounds(data: &[f32], value: f32) -> Option<usize> {
    let mut first = 0usize;
    let mut step;
    let mut count = data.len() as isize;
    while count > 0 {
        step = count / 2;
        let it = first + step as usize;
        if !value.lt(&data[it]) {
            first = it + 1;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    // If we didn't find an element greater than value
    if first == data.len() {
        None
    } else {
        Some(first)
    }
}

#[cfg(test)]
mod test {
    use std::ops::{Mul, Add};

    use super::BSpline;

    #[derive(Copy, Clone, Debug)]
    struct Point {
        x: f32,
        y: f32,
    }
    impl Point {
        fn new(x: f32, y: f32) -> Point {
            Point { x: x, y: y }
        }
    }
    impl Mul<f32> for Point {
        type Output = Point;
        fn mul(self, rhs: f32) -> Point {
            Point { x: self.x * rhs, y: self.y * rhs }
        }
    }
    impl Add for Point {
        type Output = Point;
        fn add(self, rhs: Point) -> Point {
            Point { x: self.x + rhs.x, y: self.y + rhs.y }
        }
    }

    // TODO: Test on 1D functions? Re-write tests
    #[test]
    fn linear_bspline() {
        let points = vec![Point::new(-1.0, 0.0), Point::new(0.0, 1.0),
                          Point::new(1.0, 1.0), Point::new(1.0, 2.0)];
        let knots = vec![0.0, 0.0, 1.0, 2.0, 3.0, 3.0];
        let spline = BSpline::new(1, points, knots);
        let x = spline.point(1.5);
        println!("spline(1.5) = {:?}", x);
        assert!(x.x == 0.5 && x.y == 1.0);
    }
}

<commit_msg>Add method to get knot domain to evaluate the curve over<commit_after>use std::ops::{Mul, Add};
use std::slice::Iter;

pub trait Interpolate {
    fn interpolate(&self, other: &Self, t: f32) -> Self;
}

impl<T: Mul<f32, Output = T> + Add<Output = T> + Copy> Interpolate for T {
    fn interpolate(&self, other: &Self, t: f32) -> Self {
        *self * (1.0 - t) + *other * t
    }
}

/// Structure for computing the B-spline with the given control points
/// and knots.
pub struct BSpline<T: Interpolate + Copy> {
    /// Degree of the polynomial that we use to make the curve segments
    degree: usize,
    /// Control points for the curve
    control_points: Vec<T>,
    /// TODO: What is a good description for the knots?
    knots: Vec<f32>,
}

impl<T: Interpolate + Copy> BSpline<T> {
    /// Create a new B-spline curve of the desired degree that will blend between
    /// the passed control points using the knots. The knots should be sorted in ascending
    /// order, otherwise they will be sorted for you which may lead to undesired knots
    /// for control points
    pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<f32>) -> BSpline<T> {
        // TODO: Maybe a ctor for cardinal curves that will check we have the right number of
        // knots? Is this check correct?
        if control_points.len() < degree {
            panic!("Too few control points for curve");
        }
        if knots.len() != control_points.len() + degree + 1 {
            panic!(format!("Invalid number of knots, got {}, expected {}", knots.len(),
                control_points.len() + degree + 1));
        }
        knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
        BSpline { degree: degree, control_points: control_points, knots: knots }
    }
    /// Compute a point on the curve at `t`
    /// TODO: Handling of out of bounds t values? Are t values not in the domain considered
    /// out of range? The extra `degree` values are just for when we're going down the tree
    /// to find the interpolated values there right?
    pub fn point(&self, t: f32) -> T {
        // Find the first index with a knot value greater than the t we're searching for. We want
        // to find i such that: knot[i] <= t < knot[i + 1]
        let i = match upper_bounds(&self.knots[..], t) {
            Some(x) if x == 0 => self.degree,
            Some(x) => x,
            None => self.knots.len() - self.degree - 1,
        };
        self.de_boors(t, self.degree, i)
    }
    /// Get an iterator over the control points
    pub fn control_points(&self) -> Iter<T> {
        self.control_points.iter()
    }
    /// Get an iterator over the knots
    pub fn knots(&self) -> Iter<f32> {
        self.knots.iter()
    }
    /// Get the min and max knot domain values for finding the t range to compute
    /// the curve over
    pub fn knot_domain(&self) -> (f32, f32) {
        (self.knots[self.degree], self.knots[self.knots.len() - 1 - self.degree])
    }
    /// Recursively compute de Boor's B-spline algorithm. TODO: This is not so good,
    /// compute it iteratively! Recursive version is just for a simple formualation
    /// of the initial implementation. Could we do memo-ization? If we switch to an
    /// iterative one and recursively compute the weights our interpolation at
    /// each level is no longer linear, which makes it harder to support things like
    /// Quaternions.
    fn de_boors(&self, t: f32, k: usize, i: usize) -> T {
        if k == 0 {
            self.control_points[i - 1]
        } else {
            let alpha = (t - self.knots[i - 1]) / (self.knots[i + self.degree - k] - self.knots[i - 1]);
            self.de_boors(t, k - 1, i - 1).interpolate(&self.de_boors(t, k - 1, i), alpha)
        }
    }
}

/// Return the index of the first element greater than the value passed.
/// The data **must** be sorted.
/// If no element greater than the value passed is found the function returns None.
fn upper_bounds(data: &[f32], value: f32) -> Option<usize> {
    let mut first = 0usize;
    let mut step;
    let mut count = data.len() as isize;
    while count > 0 {
        step = count / 2;
        let it = first + step as usize;
        if !value.lt(&data[it]) {
            first = it + 1;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    // If we didn't find an element greater than value
    if first == data.len() {
        None
    } else {
        Some(first)
    }
}

#[cfg(test)]
mod test {
    use std::ops::{Mul, Add};

    use super::BSpline;

    #[derive(Copy, Clone, Debug)]
    struct Point {
        x: f32,
        y: f32,
    }
    impl Point {
        fn new(x: f32, y: f32) -> Point {
            Point { x: x, y: y }
        }
    }
    impl Mul<f32> for Point {
        type Output = Point;
        fn mul(self, rhs: f32) -> Point {
            Point { x: self.x * rhs, y: self.y * rhs }
        }
    }
    impl Add for Point {
        type Output = Point;
        fn add(self, rhs: Point) -> Point {
            Point { x: self.x + rhs.x, y: self.y + rhs.y }
        }
    }

    // TODO: Test on 1D functions? Re-write tests
    #[test]
    fn linear_bspline() {
        let points = vec![Point::new(-1.0, 0.0), Point::new(0.0, 1.0),
                          Point::new(1.0, 1.0), Point::new(1.0, 2.0)];
        let knots = vec![0.0, 0.0, 1.0, 2.0, 3.0, 3.0];
        let spline = BSpline::new(1, points, knots);
        let x = spline.point(1.5);
        println!("spline(1.5) = {:?}", x);
        assert!(x.x == 0.5 && x.y == 1.0);
    }
}

<|endoftext|>