<commit_before>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! Attempt of creating a cheap drawing context.

use std::num::Float;

pub type Matrix2d = [f64, ..6];
pub type Color = [f64, ..4];

/// Implemented by all graphics back-ends.
/// This trait uses default methods to simplify implementation.
pub trait BackEnd {
    /// Returns true if 2d triangle list with color assigned per vertex is supported.
    fn supports_tri_list_xy_rgba(&self) -> bool { false }

    /// Renders list of 2d triangles with color assigned per vertex.
    fn tri_list_xy_rgba(&mut self, _vertices: &[f64], _colors: &[f64]) {}
}

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(m: &[f64, ..6], b: &[f64, ..6]) -> [f64, ..6] {
    [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
     m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
}

/// Drawing 2d context.
pub struct Context<'a> {
    base: Field<'a, Matrix2d>,
    transform: Field<'a, Matrix2d>,
    color: Field<'a, Color>,
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            color: Value([0.0, 0.0, 0.0, 1.0]),
        }
    }

    /// Returns a translated context.
    #[inline(always)]
    pub fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans: [f64, ..6] = [1.0, 0.0, x,
                                         0.0, 1.0, y];
                 multiply(&trans, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Rotates with degrees.
    #[inline(always)]
    pub fn rot_deg(&'a self, angle: f64) -> Context<'a> {
        let pi: f64 = Float::pi();
        self.rot(angle * pi / 180.0)
    }

    /// Returns a rotated context.
    #[inline(always)]
    pub fn rot(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let c = angle.cos();
                let s = angle.sin();
                let rot: [f64, ..6] = [c, s, 0.0,
                                      -s, c, 0.0];
                multiply(&rot, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a scaled context.
    #[inline(always)]
    pub fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale: [f64, ..6] = [sx, 0.0, 0.0,
                                         0.0, sy, 0.0];
                multiply(&scale, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a sheared context.
    #[inline(always)]
    pub fn shear(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear: [f64, ..6] = [1.0, sx, 0.0,
                                         sy, 1.0, 0.0];
            multiply(&shear, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}
<commit_msg>Added inline by default of supports method<commit_after>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! Attempt of creating a cheap drawing context.

use std::num::Float;

pub type Matrix2d = [f64, ..6];
pub type Color = [f64, ..4];

/// Implemented by all graphics back-ends.
/// This trait uses default methods to simplify implementation.
pub trait BackEnd {
    /// Returns true if 2d triangle list with color assigned per vertex is supported.
    #[inline(always)]
    fn supports_tri_list_xy_rgba(&self) -> bool { false }

    /// Renders list of 2d triangles with color assigned per vertex.
    fn tri_list_xy_rgba(&mut self, _vertices: &[f64], _colors: &[f64]) {}
}

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(m: &[f64, ..6], b: &[f64, ..6]) -> [f64, ..6] {
    [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
     m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
}

/// Drawing 2d context.
pub struct Context<'a> {
    base: Field<'a, Matrix2d>,
    transform: Field<'a, Matrix2d>,
    color: Field<'a, Color>,
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            color: Value([0.0, 0.0, 0.0, 1.0]),
        }
    }

    /// Returns a translated context.
    #[inline(always)]
    pub fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans: [f64, ..6] = [1.0, 0.0, x,
                                         0.0, 1.0, y];
                 multiply(&trans, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Rotates with degrees.
    #[inline(always)]
    pub fn rot_deg(&'a self, angle: f64) -> Context<'a> {
        let pi: f64 = Float::pi();
        self.rot(angle * pi / 180.0)
    }

    /// Returns a rotated context.
    #[inline(always)]
    pub fn rot(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let c = angle.cos();
                let s = angle.sin();
                let rot: [f64, ..6] = [c, s, 0.0,
                                      -s, c, 0.0];
                multiply(&rot, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a scaled context.
    #[inline(always)]
    pub fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale: [f64, ..6] = [sx, 0.0, 0.0,
                                         0.0, sy, 0.0];
                multiply(&scale, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a sheared context.
    #[inline(always)]
    pub fn shear(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear: [f64, ..6] = [1.0, sx, 0.0,
                                         sy, 1.0, 0.0];
            multiply(&shear, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}
<|endoftext|>


<commit_before>#![no_std]

#[cfg(test)]
extern crate std;

// Re-export libcore using an alias so that the macros can work in no_std
// crates while remaining compatible with normal crates.
#[allow(private_in_public)]
#[doc(hidden)]
pub use core as __core;

/** This macro can be used to ensure that a function is called only once. It panics if the function
is called a second time.

# Example

Using the macro:

```rust
#[macro_use]
extern crate once;

fn init() {
    assert_has_not_been_called!();

    // code that should only run once
}

fn main() {
    init();
    // init(); // "assertion failed: called == false"
}
```

Custom error message:

```rust
#[macro_use]
extern crate once;

fn init() {
    assert_has_not_been_called!("the init function must only be called {}", "once");
}

fn main() {
    init();
    // init(); // "the init function must only be called once"
}
```
**/
#[macro_export]
macro_rules! assert_has_not_been_called {
    () => {
        assert_has_not_been_called!("assertion failed: has_run == false");
    };
    ($($arg:tt)+) => {{
        fn assert_has_not_been_called() {
            use $crate::__core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
            static CALLED: AtomicBool = ATOMIC_BOOL_INIT;
            let called = CALLED.swap(true, Ordering::Relaxed);
            assert!(called == false, $($arg)+);
        }
        assert_has_not_been_called();
    }};
}

#[test]
fn test_run_once() {
    fn init() {
        assert_has_not_been_called!();
    }
    init();
}

#[test]
fn test_run_once_different_fns() {
    fn init1() {
        assert_has_not_been_called!();
    }
    fn init2() {
        assert_has_not_been_called!();
    }
    init1();
    init2();
}

#[test]
#[should_panic]
fn test_run_twice() {
    fn init() {
        assert_has_not_been_called!();
    }
    init();
    init();
}

#[test]
fn test_hygiene1() {
    fn init() {
        assert_has_not_been_called!();

        #[allow(dead_code)]
        fn assert_has_not_been_called() {}
    }
    init();
}

#[test]
fn test_hygiene2() {
    fn init() {
        assert_has_not_been_called!();

        #[allow(dead_code)]
        static CALLED: i32 = 42;
    }
    init();
}
<commit_msg>Fix build on nightly (#4)<commit_after>#![no_std]

#[cfg(test)]
extern crate std;

// Re-export libcore using an alias so that the macros can work in no_std
// crates while remaining compatible with normal crates.
#[doc(hidden)]
pub extern crate core as __core;

/** This macro can be used to ensure that a function is called only once. It panics if the function
is called a second time.

# Example

Using the macro:

```rust
#[macro_use]
extern crate once;

fn init() {
    assert_has_not_been_called!();

    // code that should only run once
}

fn main() {
    init();
    // init(); // "assertion failed: called == false"
}
```

Custom error message:

```rust
#[macro_use]
extern crate once;

fn init() {
    assert_has_not_been_called!("the init function must only be called {}", "once");
}

fn main() {
    init();
    // init(); // "the init function must only be called once"
}
```
**/
#[macro_export]
macro_rules! assert_has_not_been_called {
    () => {
        assert_has_not_been_called!("assertion failed: has_run == false");
    };
    ($($arg:tt)+) => {{
        fn assert_has_not_been_called() {
            use $crate::__core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
            static CALLED: AtomicBool = ATOMIC_BOOL_INIT;
            let called = CALLED.swap(true, Ordering::Relaxed);
            assert!(called == false, $($arg)+);
        }
        assert_has_not_been_called();
    }};
}

#[test]
fn test_run_once() {
    fn init() {
        assert_has_not_been_called!();
    }
    init();
}

#[test]
fn test_run_once_different_fns() {
    fn init1() {
        assert_has_not_been_called!();
    }
    fn init2() {
        assert_has_not_been_called!();
    }
    init1();
    init2();
}

#[test]
#[should_panic]
fn test_run_twice() {
    fn init() {
        assert_has_not_been_called!();
    }
    init();
    init();
}

#[test]
fn test_hygiene1() {
    fn init() {
        assert_has_not_been_called!();

        #[allow(dead_code)]
        fn assert_has_not_been_called() {}
    }
    init();
}

#[test]
fn test_hygiene2() {
    fn init() {
        assert_has_not_been_called!();

        #[allow(dead_code)]
        static CALLED: i32 = 42;
    }
    init();
}
<|endoftext|>


<commit_before>#![ feature(libc, core, collections) ]
#![ allow(non_snake_case) ]

extern crate libc;

use libusb::*;
use libc::c_int;
use std::intrinsics;
use std::slice;
use std::iter::repeat;
use std::result::Result;
use std::mem::transmute;
use std::mem::size_of;
use std::vec::Vec;
use std::cell::UnsafeCell;

pub mod libusb;

pub struct Context(*mut libusb_context);
unsafe impl Send for Context {}
unsafe impl Sync for Context {}

impl Context {
	pub fn new() -> Context {
		unsafe{
			let mut ctx: *mut libusb_context = intrinsics::init();
			let r = libusb_init(&mut ctx);
			assert!(r == 0);
			Context(ctx)
		}
	}

	pub fn ptr(&self) -> *mut libusb_context {
		self.0
	}

	pub fn set_debug(&self, level: u32) {
		unsafe{
			libusb_set_debug(self.ptr(), level as c_int);
		}
	}

	pub fn list_devices(&self) -> Vec<Device> {
		unsafe{
			let mut list: *mut *mut libusb_device = intrinsics::init();
			let num_devices = libusb_get_device_list(self.ptr(), &mut list);
			let l = slice::from_raw_parts_mut(list, num_devices as usize);
			let devices = l.iter().map(|i| Device { dev: *i, ctx: self }).collect();
			libusb_free_device_list(list, 0);
			devices
		}
	}

	pub fn find_by_vid_pid(&self, vid: u16, pid: u16) -> Option<Device> {
		self.list_devices().into_iter().find(|d| {
			let desc = d.descriptor();
			desc.idVendor == vid && desc.idProduct == pid
		})
	}
}

impl Drop for Context {
	fn drop(&mut self) {
		unsafe { libusb_exit(self.0); }
	}
}

pub struct Device<'c> {
	dev: *mut libusb_device,
	ctx: &'c Context,
}

impl<'c> Device<'c> {
	pub fn descriptor(&self) -> libusb_device_descriptor {
		unsafe{
			let mut d: libusb_device_descriptor = intrinsics::uninit();
			libusb_get_device_descriptor(self.dev, &mut d as *mut libusb_device_descriptor);
			d
		}
	}

	pub fn bus(&self) -> u8 {
		unsafe {
			libusb_get_bus_number(self.dev)
		}
	}

	pub fn address(&self) -> u8 {
		unsafe {
			libusb_get_device_address(self.dev)
		}
	}

	pub fn open(&self) -> Result<DeviceHandle, c_int> {
		unsafe {
			let mut handle: *mut libusb_device_handle = intrinsics::uninit();
			let r = libusb_open(self.dev, &mut handle);
			if r == 0 {
				Ok(DeviceHandle {
					dev: handle,
					ctx: self.ctx
				})
			}else{
				Err(r)
			}
		}
	}
}

impl<'c> Drop for Device<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_unref_device(self.dev);
		}
	}
}

impl<'c> Clone for Device<'c> {
	fn clone(&self) -> Device<'c> {
		unsafe {
			libusb_ref_device(self.dev);
		}
		Device{ dev: self.dev, ctx: self.ctx }
	}
}

pub struct DeviceHandle<'c> {
	dev: *mut libusb_device_handle,
	ctx: &'c Context
}
unsafe impl<'c> Sync for DeviceHandle<'c> {}

impl<'c> DeviceHandle<'c> {
	pub fn ptr(&self) -> *mut libusb_device_handle {
		self.dev
	}

	pub fn claim_interface(&self, iface_num: u16) {
		unsafe {
			libusb_claim_interface(self.ptr(), iface_num as c_int);
		}
	}

	pub unsafe fn submit_transfer_sync(&self,
		endpoint: u8,
		transfer_type: libusb_transfer_type,
		length: usize,
		buffer: *mut u8,
		timeout: u32) -> (libusb_transfer_status, usize) {

		let completed: UnsafeCell<c_int> = UnsafeCell::new(0);

		extern fn callback(transfer: *mut libusb_transfer) {
			unsafe {
				let completed: &UnsafeCell<c_int> = transmute((*transfer).user_data);
				*completed.get() = 1;
			}
		}

		let t = libusb_alloc_transfer(0);
		(*t).dev_handle = self.ptr();
		(*t).endpoint = endpoint;
		(*t).transfer_type = transfer_type as u8;
		(*t).timeout = timeout;
		(*t).length = length as c_int;
		(*t).callback = callback;
		(*t).user_data = transmute(&completed);
		(*t).buffer = buffer;

		libusb_submit_transfer(t);

		while *completed.get() == 0{
			libusb_handle_events_completed(self.ctx.ptr(), completed.get());
		}

		let r = ((*t).get_status(), (*t).actual_length as usize);
		libusb_free_transfer(t);
		return r;
	}

	pub fn read(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: usize,
			timeout: u32
			) -> Result<Vec<u8>, libusb_transfer_status> {
		let mut buf: Vec<u8> = repeat(0u8).take(size).collect();
		unsafe {
			let ptr = buf.as_mut_ptr();
			let (status, actual_length) = self.submit_transfer_sync(
				endpoint, transfer_type, size, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				buf.truncate(actual_length);
				Ok(buf)
			} else {
				Err(status)
			}
		}
	}

	pub fn write(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			buf: &[u8],
			timeout: u32
			) -> Result<(), libusb_transfer_status> {
		unsafe {
			let ptr = buf.as_ptr() as *mut u8;

			let (status, _) = self.submit_transfer_sync(
				endpoint, transfer_type, buf.len(), ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_read(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, length: usize, timeout: u32) -> Result<Vec<u8>, libusb_transfer_status> {

		let setup_length = size_of::<libusb_control_setup>();
		let total_length = setup_length + length;
		let mut buf: Vec<u8> = repeat(0u8).take(total_length).collect();
		let ptr = fill_setup_buf(&mut buf, bmRequestType, bRequest, wValue, wIndex, length);

		unsafe{
			let (status, actual_length) = self.submit_transfer_sync(
				0, LIBUSB_TRANSFER_TYPE_CONTROL, total_length, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(buf[setup_length..setup_length+actual_length].to_vec())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_write(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, buf: &[u8], timeout: u32) -> Result<(), libusb_transfer_status> {
		let mut setup_buf: Vec<_> = repeat(0u8).take(size_of::<libusb_control_setup>()).collect();
		fill_setup_buf(&mut setup_buf, bmRequestType, bRequest, wValue, wIndex, buf.len());
		setup_buf.push_all(buf);
		self.write(0, LIBUSB_TRANSFER_TYPE_CONTROL, &setup_buf, timeout)
	}
}

impl<'c> Drop for DeviceHandle<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_close(self.dev);
		}
	}
}

fn fill_setup_buf(buf: &mut [u8], bmRequestType: u8,
	bRequest: u8, wValue:u16, wIndex: u16, length: usize) -> *mut u8 {
	let ptr = buf.as_mut_ptr();
	let setup = ptr as *mut libusb_control_setup;

	assert!(buf.len() >= 8);
	assert!(length <= (std::u16::MAX as usize));

	unsafe {
		(*setup).bmRequestType = bmRequestType;
		(*setup).bRequest = bRequest;
		(*setup).wValue = wValue.to_le();
		(*setup).wIndex = wIndex.to_le();
		(*setup).wLength = (length as u16).to_le();
	}

	return ptr;
}
<commit_msg>rust: intrinsics::uninit -> mem::uninitialized<commit_after>#![ feature(libc, collections) ]
#![ allow(non_snake_case) ]

extern crate libc;

use libusb::*;
use libc::c_int;
use std::mem;
use std::slice;
use std::iter::repeat;
use std::result::Result;
use std::mem::transmute;
use std::mem::size_of;
use std::vec::Vec;
use std::cell::UnsafeCell;

pub mod libusb;

pub struct Context(*mut libusb_context);
unsafe impl Send for Context {}
unsafe impl Sync for Context {}

impl Context {
	pub fn new() -> Context {
		unsafe{
			let mut ctx: *mut libusb_context = mem::uninitialized();
			let r = libusb_init(&mut ctx);
			assert!(r == 0);
			Context(ctx)
		}
	}

	pub fn ptr(&self) -> *mut libusb_context {
		self.0
	}

	pub fn set_debug(&self, level: u32) {
		unsafe{
			libusb_set_debug(self.ptr(), level as c_int);
		}
	}

	pub fn list_devices(&self) -> Vec<Device> {
		unsafe{
			let mut list: *mut *mut libusb_device = mem::uninitialized();
			let num_devices = libusb_get_device_list(self.ptr(), &mut list);
			let l = slice::from_raw_parts_mut(list, num_devices as usize);
			let devices = l.iter().map(|i| Device { dev: *i, ctx: self }).collect();
			libusb_free_device_list(list, 0);
			devices
		}
	}

	pub fn find_by_vid_pid(&self, vid: u16, pid: u16) -> Option<Device> {
		self.list_devices().into_iter().find(|d| {
			let desc = d.descriptor();
			desc.idVendor == vid && desc.idProduct == pid
		})
	}
}

impl Drop for Context {
	fn drop(&mut self) {
		unsafe { libusb_exit(self.0); }
	}
}

pub struct Device<'c> {
	dev: *mut libusb_device,
	ctx: &'c Context,
}

impl<'c> Device<'c> {
	pub fn descriptor(&self) -> libusb_device_descriptor {
		unsafe{
			let mut d: libusb_device_descriptor = mem::uninitialized();
			libusb_get_device_descriptor(self.dev, &mut d as *mut libusb_device_descriptor);
			d
		}
	}

	pub fn bus(&self) -> u8 {
		unsafe {
			libusb_get_bus_number(self.dev)
		}
	}

	pub fn address(&self) -> u8 {
		unsafe {
			libusb_get_device_address(self.dev)
		}
	}

	pub fn open(&self) -> Result<DeviceHandle, c_int> {
		unsafe {
			let mut handle: *mut libusb_device_handle = mem::uninitialized();
			let r = libusb_open(self.dev, &mut handle);
			if r == 0 {
				Ok(DeviceHandle {
					dev: handle,
					ctx: self.ctx
				})
			}else{
				Err(r)
			}
		}
	}
}

impl<'c> Drop for Device<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_unref_device(self.dev);
		}
	}
}

impl<'c> Clone for Device<'c> {
	fn clone(&self) -> Device<'c> {
		unsafe {
			libusb_ref_device(self.dev);
		}
		Device{ dev: self.dev, ctx: self.ctx }
	}
}

pub struct DeviceHandle<'c> {
	dev: *mut libusb_device_handle,
	ctx: &'c Context
}
unsafe impl<'c> Sync for DeviceHandle<'c> {}

impl<'c> DeviceHandle<'c> {
	pub fn ptr(&self) -> *mut libusb_device_handle {
		self.dev
	}

	pub fn claim_interface(&self, iface_num: u16) {
		unsafe {
			libusb_claim_interface(self.ptr(), iface_num as c_int);
		}
	}

	pub unsafe fn submit_transfer_sync(&self,
		endpoint: u8,
		transfer_type: libusb_transfer_type,
		length: usize,
		buffer: *mut u8,
		timeout: u32) -> (libusb_transfer_status, usize) {

		let completed: UnsafeCell<c_int> = UnsafeCell::new(0);

		extern fn callback(transfer: *mut libusb_transfer) {
			unsafe {
				let completed: &UnsafeCell<c_int> = transmute((*transfer).user_data);
				*completed.get() = 1;
			}
		}

		let t = libusb_alloc_transfer(0);
		(*t).dev_handle = self.ptr();
		(*t).endpoint = endpoint;
		(*t).transfer_type = transfer_type as u8;
		(*t).timeout = timeout;
		(*t).length = length as c_int;
		(*t).callback = callback;
		(*t).user_data = transmute(&completed);
		(*t).buffer = buffer;

		libusb_submit_transfer(t);

		while *completed.get() == 0{
			libusb_handle_events_completed(self.ctx.ptr(), completed.get());
		}

		let r = ((*t).get_status(), (*t).actual_length as usize);
		libusb_free_transfer(t);
		return r;
	}

	pub fn read(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: usize,
			timeout: u32
			) -> Result<Vec<u8>, libusb_transfer_status> {
		let mut buf: Vec<u8> = repeat(0u8).take(size).collect();
		unsafe {
			let ptr = buf.as_mut_ptr();
			let (status, actual_length) = self.submit_transfer_sync(
				endpoint, transfer_type, size, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				buf.truncate(actual_length);
				Ok(buf)
			} else {
				Err(status)
			}
		}
	}

	pub fn write(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			buf: &[u8],
			timeout: u32
			) -> Result<(), libusb_transfer_status> {
		unsafe {
			let ptr = buf.as_ptr() as *mut u8;

			let (status, _) = self.submit_transfer_sync(
				endpoint, transfer_type, buf.len(), ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_read(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, length: usize, timeout: u32) -> Result<Vec<u8>, libusb_transfer_status> {

		let setup_length = size_of::<libusb_control_setup>();
		let total_length = setup_length + length;
		let mut buf: Vec<u8> = repeat(0u8).take(total_length).collect();
		let ptr = fill_setup_buf(&mut buf, bmRequestType, bRequest, wValue, wIndex, length);

		unsafe{
			let (status, actual_length) = self.submit_transfer_sync(
				0, LIBUSB_TRANSFER_TYPE_CONTROL, total_length, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(buf[setup_length..setup_length+actual_length].to_vec())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_write(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, buf: &[u8], timeout: u32) -> Result<(), libusb_transfer_status> {
		let mut setup_buf: Vec<_> = repeat(0u8).take(size_of::<libusb_control_setup>()).collect();
		fill_setup_buf(&mut setup_buf, bmRequestType, bRequest, wValue, wIndex, buf.len());
		setup_buf.push_all(buf);
		self.write(0, LIBUSB_TRANSFER_TYPE_CONTROL, &setup_buf, timeout)
	}
}

impl<'c> Drop for DeviceHandle<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_close(self.dev);
		}
	}
}

fn fill_setup_buf(buf: &mut [u8], bmRequestType: u8,
	bRequest: u8, wValue:u16, wIndex: u16, length: usize) -> *mut u8 {
	let ptr = buf.as_mut_ptr();
	let setup = ptr as *mut libusb_control_setup;

	assert!(buf.len() >= 8);
	assert!(length <= (std::u16::MAX as usize));

	unsafe {
		(*setup).bmRequestType = bmRequestType;
		(*setup).bRequest = bRequest;
		(*setup).wValue = wValue.to_le();
		(*setup).wIndex = wIndex.to_le();
		(*setup).wLength = (length as u16).to_le();
	}

	return ptr;
}
<|endoftext|>


<commit_before>//! `gel` is an extension of sebcrozet's `nalgebra` crate, designed to facilitate OpenGL
//! mathematics.

extern crate num;
extern crate nalgebra;
extern crate glium;
extern crate rustc_serialize;

use std::mem;
use std::ptr;

use glium::uniforms::{
    AsUniformValue,
    UniformValue,
    UniformBlock,
};
pub use num::{
    One,
    Zero,
};

pub use nalgebra::*;
/// A trait for objects able to be extended.
pub trait Extend<N> {
    type Output;

    fn extend(&self, N) -> Self::Output;
}

/// A trait for objects able to be truncated.
pub trait Truncate {
    type Output;

    fn truncate(&self) -> Self::Output;
}

/// A trait for objects able to construct view matrices.
pub trait LookAt<N> {
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self;
}

macro_rules! impl_extend {
    ($t_in:ident, $t_out:ident, {$($compN:ident),*} + $ext:ident) => {
        impl<N> Extend<N> for $t_in<N>
            where N: Copy
        {
            type Output = $t_out<N>;

            fn extend(&self, elem: N) -> Self::Output {
                unsafe {
                    let mut res: Self::Output = mem::uninitialized();
                    $(ptr::write(&mut res.$compN, self.$compN);)*
                    ptr::write(&mut res.$ext, elem);
                    res
                }
            }
        }
    }
}

macro_rules! impl_truncate {
    ($t_in:ident, $t_out:ident, {$($compN:ident),*}) => {
        impl<N> Truncate for $t_in<N>
            where N: Copy
        {
            type Output = $t_out<N>;

            fn truncate(&self) -> Self::Output {
                $t_out::new($(self.$compN),*)
            }
        }
    }
}

impl_extend!(Vec0, Vec1, {} + x);
impl_extend!(Vec1, Vec2, {x} + y);
impl_extend!(Vec2, Vec3, {x, y} + z);
impl_extend!(Vec3, Vec4, {x, y, z} + w);
impl_extend!(Vec4, Vec5, {x, y, z, w} + a);
impl_extend!(Vec5, Vec6, {x, y, z, w, a} + b);

impl_extend!(Pnt0, Pnt1, {} + x);
impl_extend!(Pnt1, Pnt2, {x} + y);
impl_extend!(Pnt2, Pnt3, {x, y} + z);
impl_extend!(Pnt3, Pnt4, {x, y, z} + w);
impl_extend!(Pnt4, Pnt5, {x, y, z, w} + a);
impl_extend!(Pnt5, Pnt6, {x, y, z, w, a} + b);

impl_truncate!(Vec1, Vec0, {});
impl_truncate!(Vec2, Vec1, {x});
impl_truncate!(Vec3, Vec2, {x, y});
impl_truncate!(Vec4, Vec3, {x, y, z});
impl_truncate!(Vec5, Vec4, {x, y, z, w});
impl_truncate!(Vec6, Vec5, {x, y, z, w, a});

impl_truncate!(Pnt1, Pnt0, {});
impl_truncate!(Pnt2, Pnt1, {x});
impl_truncate!(Pnt3, Pnt2, {x, y});
impl_truncate!(Pnt4, Pnt3, {x, y, z});
impl_truncate!(Pnt5, Pnt4, {x, y, z, w});
impl_truncate!(Pnt6, Pnt5, {x, y, z, w, a});

impl<N> LookAt<N> for Rot3<N>
    where N: BaseFloat
{
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self {
        let zaxis = (*target - *camera).normalize();
        let xaxis = zaxis.cross(up).normalize();
        let yaxis = xaxis.cross(&zaxis);

        let mat = Mat3::new(xaxis.x, xaxis.y, xaxis.z,
                            yaxis.x, yaxis.y, yaxis.z,
                            -zaxis.x, -zaxis.y, -zaxis.z);

        unsafe {
            Rot3::new_with_mat(mat)
        }
    }
}

impl<N> LookAt<N> for Iso3<N>
    where N: BaseFloat
{
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self {

        let zaxis = (*target - *camera).normalize();
        let xaxis = zaxis.cross(up).normalize();
        let yaxis = xaxis.cross(&zaxis);

        let mat = Mat3::new(xaxis.x, xaxis.y, xaxis.z,
                            yaxis.x, yaxis.y, yaxis.z,
                            -zaxis.x, -zaxis.y, -zaxis.z);

        let rotmat = unsafe {
            Rot3::new_with_mat(mat)
        };

        let tx = -(camera.dot(&xaxis));
        let ty = -(camera.dot(&yaxis));
        let tz = camera.dot(&zaxis);
        let trans = Vec3::new(tx, ty, tz);

        Iso3::new_with_rotmat(trans, rotmat)
    }
}

impl<N> LookAt<N> for Mat4<N>
    where N: BaseFloat
{
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self {

        let zaxis = (*target - *camera).normalize();
        let xaxis = zaxis.cross(up).normalize();
        let yaxis = xaxis.cross(&zaxis);

        let tx = -(camera.dot(&xaxis));
        let ty = -(camera.dot(&yaxis));
        let tz = camera.dot(&zaxis);

        let one = N::one();
        let zero = N::zero();

        Mat4::new( xaxis.x,  xaxis.y,  xaxis.z, tx,
                   yaxis.x,  yaxis.y,  yaxis.z, ty,
                  -zaxis.x, -zaxis.y, -zaxis.z, tz,
                   zero,     zero,     zero,    one,)

    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, RustcDecodable, RustcEncodable)]
pub struct Perspective<N> {
    mat: Mat4<N>,
}

impl<N> Perspective<N>
    where N: BaseFloat
{
    pub fn new(fov: N, aspect: N, znear: N, zfar: N) -> Perspective<N> {
        let one = N::one();
        let two = one + one;

        let tan_half_fov = (fov / two).tan();

        let mut mat = Mat4::zero();

        mat.m11 = one / (aspect * tan_half_fov);
        mat.m22 = one / (tan_half_fov);
        mat.m33 = -(zfar + znear) / (zfar - znear);
        mat.m43 = -one;
        mat.m34 = -(two * zfar * znear) / (zfar - znear);

        Perspective {
            mat: mat,
        }
    }

    pub fn aspect(&self) -> N {
        self.mat.m22 / self.mat.m11
    }

    pub fn set_aspect(&mut self, aspect: N) {
        self.mat.m11 = self.mat.m22 / aspect;
    }

    pub fn as_mat<'a>(&'a self) -> &'a Mat4<N> {
        &self.mat
    }

}

impl<N> Perspective<N>
    where N: BaseFloat + Clone
{
    pub fn to_mat(&self) -> Mat4<N> {
        self.mat.clone()
    }
}

impl AsUniformValue for Perspective<f32> {
    fn as_uniform_value(&self) -> UniformValue {
        let val = self.to_mat();
        UniformValue::Mat4(unsafe { mem::transmute(val) })
    }
}

impl UniformBlock for Perspective<f32> {
    fn matches(layout: &glium::program::BlockLayout, base_offset: usize)
        -> Result<(), glium::uniforms::LayoutMismatchError>
    {
        use glium::program::BlockLayout;
        use glium::uniforms::LayoutMismatchError;
        use glium::uniforms::UniformType;

        if let &BlockLayout::BasicType { ty, offset_in_buffer } = layout {
            if ty != UniformType::FloatMat4 {
                return Err(LayoutMismatchError::TypeMismatch {
                    expected: ty,
                    obtained: UniformType::FloatMat4,
                });
            }

            if offset_in_buffer != base_offset {
                return Err(LayoutMismatchError::OffsetMismatch {
                    expected: offset_in_buffer,
                    obtained: base_offset,
                });
            }

            Ok(())
        } else {
            Err(LayoutMismatchError::LayoutMismatch {
                expected: layout.clone(),
                obtained: BlockLayout::BasicType {
                    ty: UniformType::FloatMat4,
                    offset_in_buffer: base_offset,
                }
            })
        }
    }

    #[inline]
    fn build_layout(base_offset: usize) -> glium::program::BlockLayout {
        use glium::program::BlockLayout;
        use glium::uniforms::UniformType;

        BlockLayout::BasicType {
            ty: UniformType::FloatMat4,
            offset_in_buffer: base_offset,
        }
    }
}

pub trait FloatExt: BaseFloat {
    fn radians(self) -> Self {
        self * (Self::pi() / <Self as Cast<f64>>::from(180.0))
    }

    fn degrees(self) -> Self {
        self * (<Self as Cast<f64>>::from(180.0) / Self::pi())
    }
}

impl FloatExt for f32 {}
impl FloatExt for f64 {}

pub fn radians<N>(n: N) -> N
    where N: FloatExt
{
    n.radians()
}

pub fn degrees<N>(n: N) -> N
    where N: FloatExt
{
    n.degrees()
}

pub fn extend<T, N>(base: T, elem: N) -> T::Output
    where T: Extend<N>
{
    base.extend(elem)
}

pub fn truncate<T>(base: T) -> T::Output
    where T: Truncate
{
    base.truncate()
}

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

    macro_rules! test_extend {
        ($t_in:ident, $t_out:ident, $elt:ident) => {{
            let x = $t_in::zero();
            let mut t = $t_out::zero();
            t.$elt = one::<f32>();
            let n = x.extend(one());

            assert!(n.approx_eq(&t));
        }}
    }

    #[test]
    fn test_extend() {
        test_extend!(Vec0, Vec1, x);
        test_extend!(Vec1, Vec2, y);
        test_extend!(Vec2, Vec3, z);
        test_extend!(Vec3, Vec4, w);
        test_extend!(Vec4, Vec5, a);
        test_extend!(Vec5, Vec6, b);
    }

    #[test]
    fn test_radians() {
        let x = 360.0;
        let t = f32::two_pi();
        let n = x.radians();

        assert!(n.approx_eq(&t));
    }

    #[test]
    fn test_degrees() {
        let x = f32::two_pi();
        let t = 360.0;
        let n = x.degrees();

        assert!(n.approx_eq(&t));
    }

}

<commit_msg>more things<commit_after>//! `gel` is an extension of sebcrozet's `nalgebra` crate, designed to facilitate OpenGL
//! mathematics.

extern crate num;
extern crate nalgebra;
extern crate glium;
extern crate rustc_serialize;

use std::mem;
use std::ptr;

use glium::program::BlockLayout;
use glium::uniforms::{
    AsUniformValue,
    UniformValue,
    UniformBlock,
    LayoutMismatchError,
};
pub use num::{
    One,
    Zero,
};

pub use nalgebra::*;
/// A trait for objects able to be extended.
pub trait Extend<N> {
    type Output;

    fn extend(&self, N) -> Self::Output;
}

/// A trait for objects able to be truncated.
pub trait Truncate {
    type Output;

    fn truncate(&self) -> Self::Output;
}

/// A trait for objects able to construct view matrices.
pub trait LookAt<N> {
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self;
}

macro_rules! impl_extend {
    ($t_in:ident, $t_out:ident, {$($compN:ident),*} + $ext:ident) => {
        impl<N> Extend<N> for $t_in<N>
            where N: Copy
        {
            type Output = $t_out<N>;

            fn extend(&self, elem: N) -> Self::Output {
                unsafe {
                    let mut res: Self::Output = mem::uninitialized();
                    $(ptr::write(&mut res.$compN, self.$compN);)*
                    ptr::write(&mut res.$ext, elem);
                    res
                }
            }
        }
    }
}

macro_rules! impl_truncate {
    ($t_in:ident, $t_out:ident, {$($compN:ident),*}) => {
        impl<N> Truncate for $t_in<N>
            where N: Copy
        {
            type Output = $t_out<N>;

            fn truncate(&self) -> Self::Output {
                $t_out::new($(self.$compN),*)
            }
        }
    }
}

impl_extend!(Vec0, Vec1, {} + x);
impl_extend!(Vec1, Vec2, {x} + y);
impl_extend!(Vec2, Vec3, {x, y} + z);
impl_extend!(Vec3, Vec4, {x, y, z} + w);
impl_extend!(Vec4, Vec5, {x, y, z, w} + a);
impl_extend!(Vec5, Vec6, {x, y, z, w, a} + b);

impl_extend!(Pnt0, Pnt1, {} + x);
impl_extend!(Pnt1, Pnt2, {x} + y);
impl_extend!(Pnt2, Pnt3, {x, y} + z);
impl_extend!(Pnt3, Pnt4, {x, y, z} + w);
impl_extend!(Pnt4, Pnt5, {x, y, z, w} + a);
impl_extend!(Pnt5, Pnt6, {x, y, z, w, a} + b);

impl_truncate!(Vec1, Vec0, {});
impl_truncate!(Vec2, Vec1, {x});
impl_truncate!(Vec3, Vec2, {x, y});
impl_truncate!(Vec4, Vec3, {x, y, z});
impl_truncate!(Vec5, Vec4, {x, y, z, w});
impl_truncate!(Vec6, Vec5, {x, y, z, w, a});

impl_truncate!(Pnt1, Pnt0, {});
impl_truncate!(Pnt2, Pnt1, {x});
impl_truncate!(Pnt3, Pnt2, {x, y});
impl_truncate!(Pnt4, Pnt3, {x, y, z});
impl_truncate!(Pnt5, Pnt4, {x, y, z, w});
impl_truncate!(Pnt6, Pnt5, {x, y, z, w, a});

impl<N> LookAt<N> for Rot3<N>
    where N: BaseFloat
{
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self {
        let zaxis = (*target - *camera).normalize();
        let xaxis = zaxis.cross(up).normalize();
        let yaxis = xaxis.cross(&zaxis);

        let mat = Mat3::new(xaxis.x, xaxis.y, xaxis.z,
                            yaxis.x, yaxis.y, yaxis.z,
                            -zaxis.x, -zaxis.y, -zaxis.z);

        unsafe {
            Rot3::new_with_mat(mat)
        }
    }
}

impl<N> LookAt<N> for Iso3<N>
    where N: BaseFloat
{
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self {

        let zaxis = (*target - *camera).normalize();
        let xaxis = zaxis.cross(up).normalize();
        let yaxis = xaxis.cross(&zaxis);

        let mat = Mat3::new(xaxis.x, xaxis.y, xaxis.z,
                            yaxis.x, yaxis.y, yaxis.z,
                            -zaxis.x, -zaxis.y, -zaxis.z);

        let rotmat = unsafe {
            Rot3::new_with_mat(mat)
        };

        let tx = -(camera.dot(&xaxis));
        let ty = -(camera.dot(&yaxis));
        let tz = camera.dot(&zaxis);
        let trans = Vec3::new(tx, ty, tz);

        Iso3::new_with_rotmat(trans, rotmat)
    }
}

impl<N> LookAt<N> for Mat4<N>
    where N: BaseFloat
{
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self {

        let zaxis = (*target - *camera).normalize();
        let xaxis = zaxis.cross(up).normalize();
        let yaxis = xaxis.cross(&zaxis);

        let tx = -(camera.dot(&xaxis));
        let ty = -(camera.dot(&yaxis));
        let tz = camera.dot(&zaxis);

        let one = N::one();
        let zero = N::zero();

        Mat4::new( xaxis.x,  xaxis.y,  xaxis.z, tx,
                   yaxis.x,  yaxis.y,  yaxis.z, ty,
                  -zaxis.x, -zaxis.y, -zaxis.z, tz,
                   zero,     zero,     zero,    one,)

    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, RustcDecodable, RustcEncodable)]
pub struct Perspective<N> {
    mat: Mat4<N>,
}

impl<N> Perspective<N>
    where N: BaseFloat
{
    pub fn new(fov: N, aspect: N, znear: N, zfar: N) -> Perspective<N> {
        let one = N::one();
        let two = one + one;

        let tan_half_fov = (fov / two).tan();

        let mut mat = Mat4::zero();

        mat.m11 = one / (aspect * tan_half_fov);
        mat.m22 = one / (tan_half_fov);
        mat.m33 = -(zfar + znear) / (zfar - znear);
        mat.m43 = -one;
        mat.m34 = -(two * zfar * znear) / (zfar - znear);

        Perspective {
            mat: mat,
        }
    }

    pub fn aspect(&self) -> N {
        self.mat.m22 / self.mat.m11
    }

    pub fn set_aspect(&mut self, aspect: N) {
        self.mat.m11 = self.mat.m22 / aspect;
    }

    pub fn as_mat<'a>(&'a self) -> &'a Mat4<N> {
        &self.mat
    }

}

impl<N> Perspective<N>
    where N: BaseFloat + Clone
{
    pub fn to_mat(&self) -> Mat4<N> {
        self.mat.clone()
    }
}

impl AsUniformValue for Perspective<f32> {
    fn as_uniform_value(&self) -> UniformValue {
        let val = self.to_mat();
        UniformValue::Mat4(unsafe { mem::transmute(val) })
    }
}

impl UniformBlock for Perspective<f32> {
    fn matches(layout: &BlockLayout, base_offset: usize)
        -> Result<(), LayoutMismatchError>
    {
        Mat4::matches(layout, base_offset)
    }

    fn build_layout(base_offset: usize) -> glium::program::BlockLayout {
        Mat4::build_layout(base_offset)
    }
}

pub trait FloatExt: BaseFloat {
    fn radians(self) -> Self {
        self * (Self::pi() / <Self as Cast<f64>>::from(180.0))
    }

    fn degrees(self) -> Self {
        self * (<Self as Cast<f64>>::from(180.0) / Self::pi())
    }
}

impl FloatExt for f32 {}
impl FloatExt for f64 {}

pub fn radians<N>(n: N) -> N
    where N: FloatExt
{
    n.radians()
}

pub fn degrees<N>(n: N) -> N
    where N: FloatExt
{
    n.degrees()
}

pub fn extend<T, N>(base: T, elem: N) -> T::Output
    where T: Extend<N>
{
    base.extend(elem)
}

pub fn truncate<T>(base: T) -> T::Output
    where T: Truncate
{
    base.truncate()
}

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

    macro_rules! test_extend {
        ($t_in:ident, $t_out:ident, $elt:ident) => {{
            let x = $t_in::zero();
            let mut t = $t_out::zero();
            t.$elt = one::<f32>();
            let n = x.extend(one());

            assert!(n.approx_eq(&t));
        }}
    }

    #[test]
    fn test_extend() {
        test_extend!(Vec0, Vec1, x);
        test_extend!(Vec1, Vec2, y);
        test_extend!(Vec2, Vec3, z);
        test_extend!(Vec3, Vec4, w);
        test_extend!(Vec4, Vec5, a);
        test_extend!(Vec5, Vec6, b);
    }

    #[test]
    fn test_radians() {
        let x = 360.0;
        let t = f32::two_pi();
        let n = x.radians();

        assert!(n.approx_eq(&t));
    }

    #[test]
    fn test_degrees() {
        let x = f32::two_pi();
        let t = 360.0;
        let n = x.degrees();

        assert!(n.approx_eq(&t));
    }

}

<|endoftext|>


<commit_before>//! Lorem ipsum generator.
//!
//! This crate contains functions for generating pseudo-Latin lorem
//! ipsum placeholder text. The traditional lorem ipsum text start
//! like this:
//!
//! > Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
//! > eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
//! > enim ad minim veniam, quis nostrud exercitation ullamco laboris
//! > nisi ut aliquip ex ea commodo consequat. [...]
//!
//! This text is in the [`LOREM_IPSUM`] constant. Random text looking
//! like the above can be generated using the [`lipsum`] function.
//! This function allows you to generate as much text as desired and
//! each invocation will generate different text. This is done using a
//! [Markov chain] based on both the [`LOREM_IPSUM`] and
//! [`LIBER_PRIMUS`] texts. The latter constant holds the full text of
//! the first book of a work by Cicero, of which the lorem ipsum text
//! is a scrambled subset.
//!
//! The random looking text is generatd using a Markov chain of order
//! two, which simply means that the next word is based on the
//! previous two words in the input texts. The Markov chain can be
//! used with other input texts by creating an instance of
//! [`MarkovChain`] and calling its [`learn`] method.
//!
//! [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
//! [`LIBER_PRIMUS`]: constant.LIBER_PRIMUS.html
//! [`lipsum`]: fn.lipsum.html
//! [`MarkovChain`]: struct.MarkovChain.html
//! [`learn`]: struct.MarkovChain.html#method.learn
//! [Markov chain]: https://en.wikipedia.org/wiki/Markov_chain

extern crate rand;

use std::cell::RefCell;
use std::collections::HashMap;
use rand::Rng;

/// A bigram is simply two consecutive words.
pub type Bigram<'a> = (&'a str, &'a str);

/// Simple order two Markov chain implementation.
///
/// The [Markov chain] is a chain of order two, which means that it
/// will use the previous two words (a bigram) when predicting the
/// next word. This is normally enough to generate random text that
/// looks somewhat plausible. The implementation is based on
/// [Generating arbitrary text with Markov chains in Rust][blog post].
///
/// [Markov chain]: https://en.wikipedia.org/wiki/Markov_chain
/// [blog post]: https://blakewilliams.me/posts/generating-arbitrary-text-with-markov-chains-in-rust
pub struct MarkovChain<'a> {
    map: HashMap<Bigram<'a>, Vec<&'a str>>,
    rng: rand::ThreadRng,
}

impl<'a> MarkovChain<'a> {
    /// Create a new Markov chain. It will use a default thread-local
    /// random number generator.
    pub fn new() -> MarkovChain<'a> {
        MarkovChain {
            map: HashMap::new(),
            rng: rand::thread_rng(),
        }
    }

    /// Add new text to the Markov chain. This can be called several
    /// times to build up the chain.
    ///
    /// # Examples
    ///
    /// ```
    /// use lipsum::MarkovChain;
    ///
    /// let mut chain = MarkovChain::new();
    /// chain.learn("red green blue");
    /// assert_eq!(chain.words(("red", "green")), Some(&vec!["blue"]));
    ///
    /// chain.learn("red green yellow");
    /// assert_eq!(chain.words(("red", "green")), Some(&vec!["blue", "yellow"]));
    /// ```
    pub fn learn(&mut self, sentence: &'a str) {
        let words = sentence.split_whitespace().collect::<Vec<&str>>();
        for window in words.windows(3) {
            let (a, b, c) = (window[0], window[1], window[2]);
            self.map.entry((a, b)).or_insert_with(Vec::new).push(c);
        }
    }

    /// Get the possible words following the given bigram, or `None`
    /// if the state is invalid.
    ///
    /// # Examples
    ///
    /// ```
    /// use lipsum::MarkovChain;
    ///
    /// let mut chain = MarkovChain::new();
    /// chain.learn("red green blue");
    /// assert_eq!(chain.words(("red", "green")), Some(&vec!["blue"]));
    /// assert_eq!(chain.words(("foo", "bar")), None);
    /// ```
    pub fn words(&self, state: Bigram<'a>) -> Option<&Vec<&str>> {
        self.map.get(&state)
    }

    /// Generate `n` words worth of lorem ipsum text. The text will
    /// start from a random point in the Markov chain.
    ///
    /// See [`generate_from`] if you want to control the starting
    /// point for the generated text.
    ///
    /// # Examples
    ///
    /// Generating the sounds of a grandfather clock:
    ///
    /// ```
    /// use lipsum::MarkovChain;
    ///
    /// let mut chain = MarkovChain::new();
    /// chain.learn("Tick, Tock, Tick, Tock, Ding! Tick, Tock, Ding! Ding!");
    /// println!("{}", chain.generate(15));
    /// ```
    ///
    /// The output looks like this:
    ///
    /// > Ding! Tick, Tock, Tick, Tock, Ding! Ding! Tock, Ding! Tick,
    /// > Tock, Tick, Tock, Tick, Tock
    ///
    /// [`generate_from`]: struct.MarkovChain.html#method.generate_from
    pub fn generate(&mut self, n: usize) -> String {
        join_words(self.iter().take(n))
    }

    /// Generate `n` words worth of lorem ipsum text. The text will
    /// start from the given bigram.
    ///
    /// Use [`generate`] if the starting point is not important.
    ///
    /// [`generate`]: struct.MarkovChain.html#method.generate
    pub fn generate_from(&mut self, n: usize, from: Bigram<'a>) -> String {
        join_words(self.iter_from(from).take(n))
    }

    /// Make a never-ending iterator over the words in the Markov
    /// chain. The iterator starts at a random point in the chain.
    pub fn iter(&mut self) -> Words {
        let keys = self.map.keys().collect::<Vec<&(&str, &str)>>();
        let state = if keys.is_empty() {
            ("", "")
        } else {
            **self.rng.choose(&keys).unwrap()
        };
        Words {
            map: &self.map,
            rng: &mut self.rng,
            keys: keys,
            state: state,
        }
    }

    /// Make a never-ending iterator over the words in the Markov
    /// chain. The iterator starts at the given bigram.
    pub fn iter_from(&mut self, from: Bigram<'a>) -> Words {
        let keys = self.map.keys().collect::<Vec<&(&str, &str)>>();
        Words {
            map: &self.map,
            rng: &mut self.rng,
            keys: keys,
            state: from,
        }
    }
}

pub struct Words<'a> {
    map: &'a HashMap<Bigram<'a>, Vec<&'a str>>,
    rng: &'a mut rand::ThreadRng,
    keys: Vec<&'a Bigram<'a>>,
    state: Bigram<'a>,
}

impl<'a> Iterator for Words<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if self.map.is_empty() {
            return None;
        }

        let result = Some(self.state.0);

        while !self.map.contains_key(&self.state) {
            self.state = **self.rng.choose(&self.keys).unwrap();
        }
        let next_words = &self.map[&self.state];
        let next = self.rng.choose(next_words).unwrap();
        self.state = (self.state.1, next);
        result
    }
}

fn join_words<'a, I: Iterator<Item = &'a str>>(mut words: I) -> String {
    match words.next() {
        None => String::new(),
        Some(word) => {
            let mut sentence = String::from(word);
            for word in words {
                sentence.push(' ');
                sentence.push_str(word);
            }
            sentence
        }
    }
}

/// The traditional lorem ipsum text as given in [Wikipedia]. Using
/// this text alone for a Markov chain of order two doesn't work very
/// well since each bigram (two consequtive words) is followed by just
/// one other word. In other words, the Markov chain will always
/// produce the same output and recreate the lorem ipsum text
/// precisely. However, combining it with the full text in
/// [`LIBER_PRIMUS`] works well.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Lorem_ipsum
/// [`LIBER_PRIMUS`]: constant.LIBER_PRIMUS.html
pub const LOREM_IPSUM: &'static str = include_str!("lorem-ipsum.txt");

/// The first book in Cicero's work De finibus bonorum et malorum ("On
/// the ends of good and evil"). The lorem ipsum text in
/// [`LOREM_IPSUM`] is derived from part of this text.
///
/// [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
pub const LIBER_PRIMUS: &'static str = include_str!("liber-primus.txt");

thread_local! {
    // Markov chain generating lorem ipsum text.
    static LOREM_IPSUM_CHAIN: RefCell<MarkovChain<'static>> = {
        let mut chain = MarkovChain::new();
        chain.learn(LOREM_IPSUM);
        chain.learn(LIBER_PRIMUS);
        RefCell::new(chain)
    }
}

/// Generate `n` words of lorem ipsum text. The output starts with
/// "Lorem ipsum" and continues with the standard lorem ipsum text
/// from [`LOREM_IPSUM`]. The text will become random if sufficiently
/// long output is requested.
///
/// [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
pub fn lipsum(n: usize) -> String {
    LOREM_IPSUM_CHAIN.with(|cell| {
                               let mut chain = cell.borrow_mut();
                               chain.generate_from(n, ("Lorem", "ipsum"))
                           })
}

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

    #[test]
    fn starts_with_lorem_ipsum() {
        assert_eq!(&lipsum(10)[..11], "Lorem ipsum");
    }

    #[test]
    fn generate_zero_words() {
        assert_eq!(lipsum(0).split_whitespace().count(), 0);
    }

    #[test]
    fn generate_one_word() {
        assert_eq!(lipsum(1).split_whitespace().count(), 1);
    }

    #[test]
    fn generate_two_words() {
        assert_eq!(lipsum(2).split_whitespace().count(), 2);
    }

    #[test]
    fn empty_chain() {
        let mut chain = MarkovChain::new();
        assert_eq!(chain.generate(10), "");
    }

    #[test]
    fn generate_from() {
        let mut chain = MarkovChain::new();
        chain.learn("red orange yellow green blue indigo violet");
        assert_eq!(chain.generate_from(5, ("orange", "yellow")),
                   "orange yellow green blue indigo");
    }

    #[test]
    fn generate_last_bigram() {
        // The bigram "yyy zzz" will not be present in the Markov
        // chain's map, and so we will not generate "xxx yyy zzz" as
        // one would expect. The chain moves from state "xxx yyy" to
        // "yyy zzz", but sees that as invalid state and resets itsel
        // back to "xxx yyy".
        let mut chain = MarkovChain::new();
        chain.learn("xxx yyy zzz");
        // We use assert! instead of assert_ne! to support early
        // versions of Rust.
        assert!(chain.generate_from(3, ("xxx", "yyy")) != "xxx yyy zzz");
    }

    #[test]
    fn generate_from_no_panic() {
        // No panic when asked to generate a chain from a starting
        // point that doesn't exist in the chain.
        let mut chain = MarkovChain::new();
        chain.learn("foo bar baz");
        chain.generate_from(3, ("xxx", "yyy"));
    }

    #[test]
    fn chain_map() {
        let mut chain = MarkovChain::new();
        chain.learn("foo bar baz quuz");
        let map = &chain.map;

        assert_eq!(map.len(), 2);
        assert_eq!(map[&("foo", "bar")], vec!["baz"]);
        assert_eq!(map[&("bar", "baz")], vec!["quuz"]);
    }
}
<commit_msg>MarkovChain: use Rng trait for random number generator<commit_after>//! Lorem ipsum generator.
//!
//! This crate contains functions for generating pseudo-Latin lorem
//! ipsum placeholder text. The traditional lorem ipsum text start
//! like this:
//!
//! > Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
//! > eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
//! > enim ad minim veniam, quis nostrud exercitation ullamco laboris
//! > nisi ut aliquip ex ea commodo consequat. [...]
//!
//! This text is in the [`LOREM_IPSUM`] constant. Random text looking
//! like the above can be generated using the [`lipsum`] function.
//! This function allows you to generate as much text as desired and
//! each invocation will generate different text. This is done using a
//! [Markov chain] based on both the [`LOREM_IPSUM`] and
//! [`LIBER_PRIMUS`] texts. The latter constant holds the full text of
//! the first book of a work by Cicero, of which the lorem ipsum text
//! is a scrambled subset.
//!
//! The random looking text is generatd using a Markov chain of order
//! two, which simply means that the next word is based on the
//! previous two words in the input texts. The Markov chain can be
//! used with other input texts by creating an instance of
//! [`MarkovChain`] and calling its [`learn`] method.
//!
//! [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
//! [`LIBER_PRIMUS`]: constant.LIBER_PRIMUS.html
//! [`lipsum`]: fn.lipsum.html
//! [`MarkovChain`]: struct.MarkovChain.html
//! [`learn`]: struct.MarkovChain.html#method.learn
//! [Markov chain]: https://en.wikipedia.org/wiki/Markov_chain

extern crate rand;

use std::cell::RefCell;
use std::collections::HashMap;
use rand::Rng;

/// A bigram is simply two consecutive words.
pub type Bigram<'a> = (&'a str, &'a str);

/// Simple order two Markov chain implementation.
///
/// The [Markov chain] is a chain of order two, which means that it
/// will use the previous two words (a bigram) when predicting the
/// next word. This is normally enough to generate random text that
/// looks somewhat plausible. The implementation is based on
/// [Generating arbitrary text with Markov chains in Rust][blog post].
///
/// [Markov chain]: https://en.wikipedia.org/wiki/Markov_chain
/// [blog post]: https://blakewilliams.me/posts/generating-arbitrary-text-with-markov-chains-in-rust
pub struct MarkovChain<'a> {
    map: HashMap<Bigram<'a>, Vec<&'a str>>,
    rng: Box<Rng>,
}

impl<'a> MarkovChain<'a> {
    /// Create a new Markov chain. It will use a default thread-local
    /// random number generator.
    pub fn new() -> MarkovChain<'a> {
        MarkovChain {
            map: HashMap::new(),
            rng: Box::new(rand::thread_rng()),
        }
    }

    /// Add new text to the Markov chain. This can be called several
    /// times to build up the chain.
    ///
    /// # Examples
    ///
    /// ```
    /// use lipsum::MarkovChain;
    ///
    /// let mut chain = MarkovChain::new();
    /// chain.learn("red green blue");
    /// assert_eq!(chain.words(("red", "green")), Some(&vec!["blue"]));
    ///
    /// chain.learn("red green yellow");
    /// assert_eq!(chain.words(("red", "green")), Some(&vec!["blue", "yellow"]));
    /// ```
    pub fn learn(&mut self, sentence: &'a str) {
        let words = sentence.split_whitespace().collect::<Vec<&str>>();
        for window in words.windows(3) {
            let (a, b, c) = (window[0], window[1], window[2]);
            self.map.entry((a, b)).or_insert_with(Vec::new).push(c);
        }
    }

    /// Get the possible words following the given bigram, or `None`
    /// if the state is invalid.
    ///
    /// # Examples
    ///
    /// ```
    /// use lipsum::MarkovChain;
    ///
    /// let mut chain = MarkovChain::new();
    /// chain.learn("red green blue");
    /// assert_eq!(chain.words(("red", "green")), Some(&vec!["blue"]));
    /// assert_eq!(chain.words(("foo", "bar")), None);
    /// ```
    pub fn words(&self, state: Bigram<'a>) -> Option<&Vec<&str>> {
        self.map.get(&state)
    }

    /// Generate `n` words worth of lorem ipsum text. The text will
    /// start from a random point in the Markov chain.
    ///
    /// See [`generate_from`] if you want to control the starting
    /// point for the generated text.
    ///
    /// # Examples
    ///
    /// Generating the sounds of a grandfather clock:
    ///
    /// ```
    /// use lipsum::MarkovChain;
    ///
    /// let mut chain = MarkovChain::new();
    /// chain.learn("Tick, Tock, Tick, Tock, Ding! Tick, Tock, Ding! Ding!");
    /// println!("{}", chain.generate(15));
    /// ```
    ///
    /// The output looks like this:
    ///
    /// > Ding! Tick, Tock, Tick, Tock, Ding! Ding! Tock, Ding! Tick,
    /// > Tock, Tick, Tock, Tick, Tock
    ///
    /// [`generate_from`]: struct.MarkovChain.html#method.generate_from
    pub fn generate(&mut self, n: usize) -> String {
        join_words(self.iter().take(n))
    }

    /// Generate `n` words worth of lorem ipsum text. The text will
    /// start from the given bigram.
    ///
    /// Use [`generate`] if the starting point is not important.
    ///
    /// [`generate`]: struct.MarkovChain.html#method.generate
    pub fn generate_from(&mut self, n: usize, from: Bigram<'a>) -> String {
        join_words(self.iter_from(from).take(n))
    }

    /// Make a never-ending iterator over the words in the Markov
    /// chain. The iterator starts at a random point in the chain.
    pub fn iter(&mut self) -> Words {
        let keys = self.map.keys().collect::<Vec<&(&str, &str)>>();
        let state = if keys.is_empty() {
            ("", "")
        } else {
            **choose(&mut self.rng, &keys).unwrap()
        };
        Words {
            map: &self.map,
            rng: &mut self.rng,
            keys: keys,
            state: state,
        }
    }

    /// Make a never-ending iterator over the words in the Markov
    /// chain. The iterator starts at the given bigram.
    pub fn iter_from(&mut self, from: Bigram<'a>) -> Words {
        let keys = self.map.keys().collect::<Vec<&(&str, &str)>>();
        Words {
            map: &self.map,
            rng: &mut self.rng,
            keys: keys,
            state: from,
        }
    }
}

pub struct Words<'a> {
    map: &'a HashMap<Bigram<'a>, Vec<&'a str>>,
    rng: &'a mut rand::Rng,
    keys: Vec<&'a Bigram<'a>>,
    state: Bigram<'a>,
}

impl<'a> Iterator for Words<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if self.map.is_empty() {
            return None;
        }

        let result = Some(self.state.0);

        while !self.map.contains_key(&self.state) {
            self.state = **choose(self.rng, &self.keys).unwrap();
        }
        let next_words = &self.map[&self.state];
        let next = choose(self.rng, next_words).unwrap();
        self.state = (self.state.1, next);
        result
    }
}

/// Choose a random element from a slice.
///
/// Unlike `Rng::choose`, this function does not require the RNG to be
/// Sized and thus works on any random number generator.
fn choose<'a, T>(rng: &mut Rng, values: &'a [T]) -> Option<&'a T> {
    if values.is_empty() {
        None
    } else {
        let idx = (values.len() as f32 * rng.next_f32()) as usize;
        Some(&values[idx])
    }
}

fn join_words<'a, I: Iterator<Item = &'a str>>(mut words: I) -> String {
    match words.next() {
        None => String::new(),
        Some(word) => {
            let mut sentence = String::from(word);
            for word in words {
                sentence.push(' ');
                sentence.push_str(word);
            }
            sentence
        }
    }
}

/// The traditional lorem ipsum text as given in [Wikipedia]. Using
/// this text alone for a Markov chain of order two doesn't work very
/// well since each bigram (two consequtive words) is followed by just
/// one other word. In other words, the Markov chain will always
/// produce the same output and recreate the lorem ipsum text
/// precisely. However, combining it with the full text in
/// [`LIBER_PRIMUS`] works well.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Lorem_ipsum
/// [`LIBER_PRIMUS`]: constant.LIBER_PRIMUS.html
pub const LOREM_IPSUM: &'static str = include_str!("lorem-ipsum.txt");

/// The first book in Cicero's work De finibus bonorum et malorum ("On
/// the ends of good and evil"). The lorem ipsum text in
/// [`LOREM_IPSUM`] is derived from part of this text.
///
/// [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
pub const LIBER_PRIMUS: &'static str = include_str!("liber-primus.txt");

thread_local! {
    // Markov chain generating lorem ipsum text.
    static LOREM_IPSUM_CHAIN: RefCell<MarkovChain<'static>> = {
        let mut chain = MarkovChain::new();
        chain.learn(LOREM_IPSUM);
        chain.learn(LIBER_PRIMUS);
        RefCell::new(chain)
    }
}

/// Generate `n` words of lorem ipsum text. The output starts with
/// "Lorem ipsum" and continues with the standard lorem ipsum text
/// from [`LOREM_IPSUM`]. The text will become random if sufficiently
/// long output is requested.
///
/// [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
pub fn lipsum(n: usize) -> String {
    LOREM_IPSUM_CHAIN.with(|cell| {
                               let mut chain = cell.borrow_mut();
                               chain.generate_from(n, ("Lorem", "ipsum"))
                           })
}

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

    #[test]
    fn starts_with_lorem_ipsum() {
        assert_eq!(&lipsum(10)[..11], "Lorem ipsum");
    }

    #[test]
    fn generate_zero_words() {
        assert_eq!(lipsum(0).split_whitespace().count(), 0);
    }

    #[test]
    fn generate_one_word() {
        assert_eq!(lipsum(1).split_whitespace().count(), 1);
    }

    #[test]
    fn generate_two_words() {
        assert_eq!(lipsum(2).split_whitespace().count(), 2);
    }

    #[test]
    fn empty_chain() {
        let mut chain = MarkovChain::new();
        assert_eq!(chain.generate(10), "");
    }

    #[test]
    fn generate_from() {
        let mut chain = MarkovChain::new();
        chain.learn("red orange yellow green blue indigo violet");
        assert_eq!(chain.generate_from(5, ("orange", "yellow")),
                   "orange yellow green blue indigo");
    }

    #[test]
    fn generate_last_bigram() {
        // The bigram "yyy zzz" will not be present in the Markov
        // chain's map, and so we will not generate "xxx yyy zzz" as
        // one would expect. The chain moves from state "xxx yyy" to
        // "yyy zzz", but sees that as invalid state and resets itsel
        // back to "xxx yyy".
        let mut chain = MarkovChain::new();
        chain.learn("xxx yyy zzz");
        // We use assert! instead of assert_ne! to support early
        // versions of Rust.
        assert!(chain.generate_from(3, ("xxx", "yyy")) != "xxx yyy zzz");
    }

    #[test]
    fn generate_from_no_panic() {
        // No panic when asked to generate a chain from a starting
        // point that doesn't exist in the chain.
        let mut chain = MarkovChain::new();
        chain.learn("foo bar baz");
        chain.generate_from(3, ("xxx", "yyy"));
    }

    #[test]
    fn chain_map() {
        let mut chain = MarkovChain::new();
        chain.learn("foo bar baz quuz");
        let map = &chain.map;

        assert_eq!(map.len(), 2);
        assert_eq!(map[&("foo", "bar")], vec!["baz"]);
        assert_eq!(map[&("bar", "baz")], vec!["quuz"]);
    }
}
<|endoftext|>


<commit_before>extern crate nom_lua53;

use nom_lua53::{parse_all, ParseResult, Statement};
use nom_lua53::name::VarName;

mod expression;
mod types;

#[derive(PartialEq, Eq, Debug, Clone)]
pub enum LuaError {
    TypeError(String),
    IndexError(String),
    ArithmeticError(String),
    OtherError(String),
    NotImplementedError,
}

type Result<T> = std::result::Result<T, LuaError>;

pub fn var_to_string(var: &VarName) -> String {
    String::from_utf8_lossy(var.0).to_string()
}

pub fn parse_statement(stmt: &Statement, ctx: &mut types::LuaState) -> Result<()> {
    match stmt {
        &Statement::LVarAssign(ref ass) => {
            let values = ass.vals
                .as_ref()
                .expect("There should be some values. Why isn't there any value?!");
            for (var, val) in ass.vars.iter().zip(values.iter()) {
                let computed_value = expression::eval_expr(val, &ctx);
                let local_scope = ctx.get_mutable_local_scope().unwrap();
                local_scope.set_string(var_to_string(var), &computed_value.unwrap());
            }
        }
        &Statement::Assignment(ref ass) => {
            let mut values = Vec::with_capacity(ass.vals.len());
            for exp in ass.vals.iter() {
                values.push(expression::eval_expr(&exp, &ctx)?);
            }

            for (prefexp, val) in ass.vars.iter().zip(values.drain(..)) {
                let assignment = expression::prefixexp::resolve_prefix_expr(
                    &prefexp.prefix,
                    &prefexp.suffix_chain,
                    ctx,
                )?;
                assignment.environment.set(&assignment.index, &val)?;
            }
            println!("Assigning {:?} to {:?}", ass.vals, ass.vars);
        }
        _ => {}
    }
    return Ok(());
}

pub fn eval_file(input: &[u8]) -> Result<()> {
    let mut ctx = types::LuaState::new();
    match parse_all(input) {
        ParseResult::Done(blk) => {
            for stmt in blk.stmts {
                println!("{:?}", stmt);
                parse_statement(&stmt, &mut ctx)?;
            }
            println!("{:?}", ctx.get_local_scope());
            println!("{:?}", ctx);
        }

        ParseResult::Error(rest, ss) => {
            println!("Error. statements == {:#?}", ss);
            println!("rest == '{}'", String::from_utf8_lossy(rest));
        }
    };
    return Ok(());
}
<commit_msg>Add trivial semicolon support<commit_after>extern crate nom_lua53;

use nom_lua53::{parse_all, ParseResult, Statement};
use nom_lua53::name::VarName;

mod expression;
mod types;

#[derive(PartialEq, Eq, Debug, Clone)]
pub enum LuaError {
    TypeError(String),
    IndexError(String),
    ArithmeticError(String),
    OtherError(String),
    NotImplementedError,
}

type Result<T> = std::result::Result<T, LuaError>;

pub fn var_to_string(var: &VarName) -> String {
    String::from_utf8_lossy(var.0).to_string()
}

pub fn parse_statement(stmt: &Statement, ctx: &mut types::LuaState) -> Result<()> {
    match stmt {
        &Statement::LVarAssign(ref ass) => {
            let values = ass.vals
                .as_ref()
                .expect("There should be some values. Why isn't there any value?!");
            for (var, val) in ass.vars.iter().zip(values.iter()) {
                let computed_value = expression::eval_expr(val, &ctx);
                let local_scope = ctx.get_mutable_local_scope().unwrap();
                local_scope.set_string(var_to_string(var), &computed_value.unwrap());
            }
        }
        &Statement::Assignment(ref ass) => {
            let mut values = Vec::with_capacity(ass.vals.len());
            for exp in ass.vals.iter() {
                values.push(expression::eval_expr(&exp, &ctx)?);
            }

            for (prefexp, val) in ass.vars.iter().zip(values.drain(..)) {
                let assignment = expression::prefixexp::resolve_prefix_expr(
                    &prefexp.prefix,
                    &prefexp.suffix_chain,
                    ctx,
                )?;
                assignment.environment.set(&assignment.index, &val)?;
            }
            println!("Assigning {:?} to {:?}", ass.vals, ass.vars);
        }
        &Statement::Semicolon => {
            println!("Semicolon...");
        }
        _ => {}
    }
    return Ok(());
}

pub fn eval_file(input: &[u8]) -> Result<()> {
    let mut ctx = types::LuaState::new();
    match parse_all(input) {
        ParseResult::Done(blk) => {
            for stmt in blk.stmts {
                println!("{:?}", stmt);
                parse_statement(&stmt, &mut ctx)?;
            }
            println!("{:?}", ctx.get_local_scope());
            println!("{:?}", ctx);
        }

        ParseResult::Error(rest, ss) => {
            println!("Error. statements == {:#?}", ss);
            println!("rest == '{}'", String::from_utf8_lossy(rest));
        }
    };
    return Ok(());
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::c_void;

mod context;
mod ffi;
mod measure;
mod measures;

pub use self::ffi::Align;
pub use self::ffi::Dimensions;
pub use self::ffi::Direction;
pub use self::ffi::Edge;
pub use self::ffi::ExperimentalFeature;
pub use self::ffi::FlexDirection;
pub use self::ffi::FlexWrap;
pub use self::ffi::JustifyContent;
pub use self::ffi::LogLevel;
pub use self::ffi::MeasureMode;
pub use self::ffi::Overflow;
pub use self::ffi::PositionType;
pub use self::ffi::PrintOptions;
pub use self::ffi::Size;

pub use context::Context;
pub use measures::Measures;

use measure::measure;

#[derive(Debug)]
pub struct Node {
    _node: *mut ffi::Node,
}

impl Node {
    pub fn new() -> Node {
        Node { _node: unsafe { ffi::YGNodeNew() } }
    }

    pub fn get_instance_count() -> i32 {
        unsafe { ffi::YGNodeGetInstanceCount() }
    }

    pub fn reset(&mut self) {
        unsafe { ffi::YGNodeReset(self._node) }
    }

    pub fn free(self) {
        unsafe { ffi::YGNodeFree(self._node) }
    }

    pub fn free_recursive(self) {
        unsafe { ffi::YGNodeFreeRecursive(self._node) }
    }

    pub fn set_direction(&mut self, value: ffi::Direction) {
        unsafe { ffi::YGNodeStyleSetDirection(self._node, value) }
    }

    pub fn get_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeStyleGetDirection(self._node) }
    }

    pub fn set_flex_direction(&mut self, value: ffi::FlexDirection) {
        unsafe { ffi::YGNodeStyleSetFlexDirection(self._node, value) }
    }

    pub fn get_flex_direction(&self) -> ffi::FlexDirection {
        unsafe { ffi::YGNodeStyleGetFlexDirection(self._node) }
    }

    pub fn set_width(&mut self, width: f32) {
        unsafe { ffi::YGNodeStyleSetWidth(self._node, width) }
    }

    pub fn get_width(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetWidth(self._node) }
    }

    pub fn set_height(&mut self, height: f32) {
        unsafe { ffi::YGNodeStyleSetHeight(self._node, height) }
    }

    pub fn get_height(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetHeight(self._node) }
    }

    pub fn calculate_layout(&mut self) {
        unsafe {
            ffi::YGNodeCalculateLayout(self._node, std::f32::NAN, std::f32::NAN, Direction::LTR)
        }
    }

    pub fn get_layout_width(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetWidth(self._node) }
    }

    pub fn get_layout_height(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetHeight(self._node) }
    }

    pub fn get_layout_left(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetLeft(self._node) }
    }

    pub fn get_layout_top(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetTop(self._node) }
    }

    pub fn get_layout_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeLayoutGetDirection(self._node) }
    }

    pub fn insert_child(&mut self, child: &Node, index: u32) {
        unsafe { ffi::YGNodeInsertChild(self._node, child._node, index) }
    }

    pub fn remove_child(&mut self, child: &Node) {
        unsafe { ffi::YGNodeRemoveChild(self._node, child._node) }
    }

    pub fn get_child(&self, index: u32) -> Node {
        unsafe { Node { _node: ffi::YGNodeGetChild(self._node, index) } }
    }

    pub fn get_child_count(&self) -> u32 {
        unsafe { ffi::YGNodeGetChildCount(self._node) }
    }

    pub fn get_parent(&self) -> Node {
        unsafe { Node { _node: ffi::YGNodeGetParent(self._node) } }
    }

    pub fn set_justify_content(&mut self, value: ffi::JustifyContent) {
        unsafe { ffi::YGNodeStyleSetJustifyContent(self._node, value) }
    }

    pub fn get_justify_content(&self) -> ffi::JustifyContent {
        unsafe { ffi::YGNodeStyleGetJustifyContent(self._node) }
    }

    pub fn get_align_items(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignItems(self._node) }
    }

    pub fn set_align_items(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignItems(self._node, value) }
    }

    pub fn get_align_self(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignSelf(self._node) }
    }

    pub fn set_align_self(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignSelf(self._node, value) }
    }

    pub fn get_align_content(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignContent(self._node) }
    }

    pub fn set_align_content(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignContent(self._node, value) }
    }

    pub fn get_position_type(&self) -> ffi::PositionType {
        unsafe { ffi::YGNodeStyleGetPositionType(self._node) }
    }

    pub fn set_position_type(&mut self, value: ffi::PositionType) {
        unsafe { ffi::YGNodeStyleSetPositionType(self._node, value) }
    }

    pub fn get_flex_wrap(&self) -> ffi::FlexWrap {
        unsafe { ffi::YGNodeStyleGetFlexWrap(self._node) }
    }

    pub fn set_flex_wrap(&mut self, value: ffi::FlexWrap) {
        unsafe { ffi::YGNodeStyleSetFlexWrap(self._node, value) }
    }

    pub fn get_overflow(&self) -> ffi::Overflow {
        unsafe { ffi::YGNodeStyleGetOverflow(self._node) }
    }

    pub fn set_overflow(&mut self, value: ffi::Overflow) {
        unsafe { ffi::YGNodeStyleSetOverflow(self._node, value) }
    }

    pub fn set_flex(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlex(self._node, value) }
    }

    pub fn get_flex_grow(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexGrow(self._node) }
    }

    pub fn set_flex_grow(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexGrow(self._node, value) }
    }

    pub fn get_flex_shrink(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexShrink(self._node) }
    }

    pub fn set_flex_shrink(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexShrink(self._node, value) }
    }

    pub fn get_flex_basis(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexBasis(self._node) }
    }

    pub fn set_flex_basis(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexBasis(self._node, value) }
    }

    pub fn get_margin(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetMargin(self._node, edge) }
    }

    pub fn set_margin(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetMargin(self._node, edge, value) }
    }

    pub fn get_padding(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPadding(self._node, edge) }
    }

    pub fn set_padding(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPadding(self._node, edge, value) }
    }

    pub fn get_border(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetBorder(self._node, edge) }
    }

    pub fn set_border(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetBorder(self._node, edge, value) }
    }

    pub fn get_position(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPosition(self._node, edge) }
    }

    pub fn set_position(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPosition(self._node, edge, value) }
    }

    pub fn set_measure_func(&mut self,
                            func: extern "C" fn(*mut ffi::Node,
                                                f32,
                                                MeasureMode,
                                                f32,
                                                MeasureMode)
                                                -> Size) {
        unsafe { ffi::YGNodeSetMeasureFunc(self._node, func) }
    }

    pub fn mark_dirty(&mut self) {
        unsafe { ffi::YGNodeMarkDirty(self._node) }
    }

    pub fn is_dirty(&self) -> bool {
        unsafe { ffi::YGNodeIsDirty(self._node) }
    }

    pub fn set_context(&mut self, context: *mut Context) {
        unsafe { ffi::YGNodeSetContext(self._node, context as *mut c_void) }
    }

    pub fn get_context(&self) -> &Context {
        unsafe {
            let context = ffi::YGNodeGetContext(self._node);
            let ref ctx: Context = *(context as *mut Context);
            ctx
        }
    }
}

#[cfg(test)]
mod tests {
    use Context;
    use Measures;
    use Node;
    use Size;
    use measure;

    struct Measurer {}

    impl Measures for Measurer {
        fn measure(&self, text: &str) -> Size {
            Size {
                width: text.len() as f32,
                height: 1.0,
            }
        }
    }

    #[test]
    fn dirty_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        assert!(!node.is_dirty());
        node.mark_dirty();
        assert!(node.is_dirty());
        node.free();
    }

    #[test]
    fn context_works() {
        let mut node = Node::new();
        node.set_context(&mut Context::new("Yo!", &Measurer {}));
        {
            let context = node.get_context();
            assert!(context.measure().width == 3.0);
        }
        node.free();
    }

    #[test]
    fn measure_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        node.set_context(&mut Context::new("Yo!!", &Measurer {}));
        node.calculate_layout();
        assert!(node.get_layout_width() == 4.0);
        assert!(node.get_layout_height() == 1.0);
        node.free();
    }

    #[test]
    fn get_instance_count() {
        assert!(Node::get_instance_count() == 0);
        let mut node = Node::new();
        assert!(Node::get_instance_count() == 1);
        node.free();
        assert!(Node::get_instance_count() == 0);
    }

    #[test]
    fn get_child_count() {
        let mut p1 = Node::new();
        let mut c1 = Node::new();
        let mut c2 = Node::new();
        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);
        assert!(p1.get_child_count() == 2);
        p1.free();
        c1.free();
        c2.free();
    }

    #[test]
    fn get_child() {
        let mut p1 = Node::new();

        let mut c1 = Node::new();
        c1.set_width(1.0);

        let mut c2 = Node::new();
        c2.set_width(2.0);

        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);

        assert!(p1.get_child(0).get_width() == 1.0);
        assert!(p1.get_child(1).get_width() == 2.0);
        p1.free();
        c1.free();
        c2.free();
    }
}
<commit_msg>chore(style): remove unneeded self<commit_after>extern crate libc;

use libc::c_void;

mod context;
mod ffi;
mod measure;
mod measures;

pub use ffi::Align;
pub use ffi::Dimensions;
pub use ffi::Direction;
pub use ffi::Edge;
pub use ffi::ExperimentalFeature;
pub use ffi::FlexDirection;
pub use ffi::FlexWrap;
pub use ffi::JustifyContent;
pub use ffi::LogLevel;
pub use ffi::MeasureMode;
pub use ffi::Overflow;
pub use ffi::PositionType;
pub use ffi::PrintOptions;
pub use ffi::Size;

pub use context::Context;
pub use measures::Measures;

use measure::measure;

#[derive(Debug)]
pub struct Node {
    _node: *mut ffi::Node,
}

impl Node {
    pub fn new() -> Node {
        Node { _node: unsafe { ffi::YGNodeNew() } }
    }

    pub fn get_instance_count() -> i32 {
        unsafe { ffi::YGNodeGetInstanceCount() }
    }

    pub fn reset(&mut self) {
        unsafe { ffi::YGNodeReset(self._node) }
    }

    pub fn free(self) {
        unsafe { ffi::YGNodeFree(self._node) }
    }

    pub fn free_recursive(self) {
        unsafe { ffi::YGNodeFreeRecursive(self._node) }
    }

    pub fn set_direction(&mut self, value: ffi::Direction) {
        unsafe { ffi::YGNodeStyleSetDirection(self._node, value) }
    }

    pub fn get_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeStyleGetDirection(self._node) }
    }

    pub fn set_flex_direction(&mut self, value: ffi::FlexDirection) {
        unsafe { ffi::YGNodeStyleSetFlexDirection(self._node, value) }
    }

    pub fn get_flex_direction(&self) -> ffi::FlexDirection {
        unsafe { ffi::YGNodeStyleGetFlexDirection(self._node) }
    }

    pub fn set_width(&mut self, width: f32) {
        unsafe { ffi::YGNodeStyleSetWidth(self._node, width) }
    }

    pub fn get_width(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetWidth(self._node) }
    }

    pub fn set_height(&mut self, height: f32) {
        unsafe { ffi::YGNodeStyleSetHeight(self._node, height) }
    }

    pub fn get_height(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetHeight(self._node) }
    }

    pub fn calculate_layout(&mut self) {
        unsafe {
            ffi::YGNodeCalculateLayout(self._node, std::f32::NAN, std::f32::NAN, Direction::LTR)
        }
    }

    pub fn get_layout_width(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetWidth(self._node) }
    }

    pub fn get_layout_height(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetHeight(self._node) }
    }

    pub fn get_layout_left(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetLeft(self._node) }
    }

    pub fn get_layout_top(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetTop(self._node) }
    }

    pub fn get_layout_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeLayoutGetDirection(self._node) }
    }

    pub fn insert_child(&mut self, child: &Node, index: u32) {
        unsafe { ffi::YGNodeInsertChild(self._node, child._node, index) }
    }

    pub fn remove_child(&mut self, child: &Node) {
        unsafe { ffi::YGNodeRemoveChild(self._node, child._node) }
    }

    pub fn get_child(&self, index: u32) -> Node {
        unsafe { Node { _node: ffi::YGNodeGetChild(self._node, index) } }
    }

    pub fn get_child_count(&self) -> u32 {
        unsafe { ffi::YGNodeGetChildCount(self._node) }
    }

    pub fn get_parent(&self) -> Node {
        unsafe { Node { _node: ffi::YGNodeGetParent(self._node) } }
    }

    pub fn set_justify_content(&mut self, value: ffi::JustifyContent) {
        unsafe { ffi::YGNodeStyleSetJustifyContent(self._node, value) }
    }

    pub fn get_justify_content(&self) -> ffi::JustifyContent {
        unsafe { ffi::YGNodeStyleGetJustifyContent(self._node) }
    }

    pub fn get_align_items(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignItems(self._node) }
    }

    pub fn set_align_items(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignItems(self._node, value) }
    }

    pub fn get_align_self(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignSelf(self._node) }
    }

    pub fn set_align_self(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignSelf(self._node, value) }
    }

    pub fn get_align_content(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignContent(self._node) }
    }

    pub fn set_align_content(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignContent(self._node, value) }
    }

    pub fn get_position_type(&self) -> ffi::PositionType {
        unsafe { ffi::YGNodeStyleGetPositionType(self._node) }
    }

    pub fn set_position_type(&mut self, value: ffi::PositionType) {
        unsafe { ffi::YGNodeStyleSetPositionType(self._node, value) }
    }

    pub fn get_flex_wrap(&self) -> ffi::FlexWrap {
        unsafe { ffi::YGNodeStyleGetFlexWrap(self._node) }
    }

    pub fn set_flex_wrap(&mut self, value: ffi::FlexWrap) {
        unsafe { ffi::YGNodeStyleSetFlexWrap(self._node, value) }
    }

    pub fn get_overflow(&self) -> ffi::Overflow {
        unsafe { ffi::YGNodeStyleGetOverflow(self._node) }
    }

    pub fn set_overflow(&mut self, value: ffi::Overflow) {
        unsafe { ffi::YGNodeStyleSetOverflow(self._node, value) }
    }

    pub fn set_flex(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlex(self._node, value) }
    }

    pub fn get_flex_grow(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexGrow(self._node) }
    }

    pub fn set_flex_grow(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexGrow(self._node, value) }
    }

    pub fn get_flex_shrink(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexShrink(self._node) }
    }

    pub fn set_flex_shrink(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexShrink(self._node, value) }
    }

    pub fn get_flex_basis(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexBasis(self._node) }
    }

    pub fn set_flex_basis(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexBasis(self._node, value) }
    }

    pub fn get_margin(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetMargin(self._node, edge) }
    }

    pub fn set_margin(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetMargin(self._node, edge, value) }
    }

    pub fn get_padding(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPadding(self._node, edge) }
    }

    pub fn set_padding(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPadding(self._node, edge, value) }
    }

    pub fn get_border(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetBorder(self._node, edge) }
    }

    pub fn set_border(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetBorder(self._node, edge, value) }
    }

    pub fn get_position(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPosition(self._node, edge) }
    }

    pub fn set_position(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPosition(self._node, edge, value) }
    }

    pub fn set_measure_func(&mut self,
                            func: extern "C" fn(*mut ffi::Node,
                                                f32,
                                                MeasureMode,
                                                f32,
                                                MeasureMode)
                                                -> Size) {
        unsafe { ffi::YGNodeSetMeasureFunc(self._node, func) }
    }

    pub fn mark_dirty(&mut self) {
        unsafe { ffi::YGNodeMarkDirty(self._node) }
    }

    pub fn is_dirty(&self) -> bool {
        unsafe { ffi::YGNodeIsDirty(self._node) }
    }

    pub fn set_context(&mut self, context: *mut Context) {
        unsafe { ffi::YGNodeSetContext(self._node, context as *mut c_void) }
    }

    pub fn get_context(&self) -> &Context {
        unsafe {
            let context = ffi::YGNodeGetContext(self._node);
            let ref ctx: Context = *(context as *mut Context);
            ctx
        }
    }
}

#[cfg(test)]
mod tests {
    use Context;
    use Measures;
    use Node;
    use Size;
    use measure;

    struct Measurer {}

    impl Measures for Measurer {
        fn measure(&self, text: &str) -> Size {
            Size {
                width: text.len() as f32,
                height: 1.0,
            }
        }
    }

    #[test]
    fn dirty_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        assert!(!node.is_dirty());
        node.mark_dirty();
        assert!(node.is_dirty());
        node.free();
    }

    #[test]
    fn context_works() {
        let mut node = Node::new();
        node.set_context(&mut Context::new("Yo!", &Measurer {}));
        {
            let context = node.get_context();
            assert!(context.measure().width == 3.0);
        }
        node.free();
    }

    #[test]
    fn measure_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        node.set_context(&mut Context::new("Yo!!", &Measurer {}));
        node.calculate_layout();
        assert!(node.get_layout_width() == 4.0);
        assert!(node.get_layout_height() == 1.0);
        node.free();
    }

    #[test]
    fn get_instance_count() {
        assert!(Node::get_instance_count() == 0);
        let mut node = Node::new();
        assert!(Node::get_instance_count() == 1);
        node.free();
        assert!(Node::get_instance_count() == 0);
    }

    #[test]
    fn get_child_count() {
        let mut p1 = Node::new();
        let mut c1 = Node::new();
        let mut c2 = Node::new();
        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);
        assert!(p1.get_child_count() == 2);
        p1.free();
        c1.free();
        c2.free();
    }

    #[test]
    fn get_child() {
        let mut p1 = Node::new();

        let mut c1 = Node::new();
        c1.set_width(1.0);

        let mut c2 = Node::new();
        c2.set_width(2.0);

        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);

        assert!(p1.get_child(0).get_width() == 1.0);
        assert!(p1.get_child(1).get_width() == 2.0);
        p1.free();
        c1.free();
        c2.free();
    }
}
<|endoftext|>