emojicode 0.1.4

Convenience wrappers for emojicode-sys
Documentation
#![feature(pointer_methods)]

extern crate emojicode_sys;

pub use emojicode_sys::*;
use std::ffi::{CStr, CString};
use std::ptr;

/// Given the major and minor version this generate the package version.
/// 
/// Example:
/// ```rust
/// package_version!(0, 1);
/// ```
#[macro_export]
macro_rules! package_version {
    ($maj:expr, $min:expr) => {
        #[no_mangle]
        #[allow(non_upper_case_globals)]
        pub static version: Emojicode_PackageVersion = Emojicode_PackageVersion { major: $maj, minor: $min };
    };
}

/// Shorthand for defining functions compatible with the linking table, and an accompanying linking
/// table.
/// 
/// Example:
/// ```rust
/// emoji_functions!(
///     hello_world(thread) {
///         println!("Hello from Rust!");
///         thread.return_from_function();
///     }
/// );
/// ```
#[macro_export]
macro_rules! emoji_functions {
    (
        $($name:ident ($t:ident) $b:block),+
    ) => {
        $(
            unsafe extern "C" fn $name($t : *mut Emojicode_Thread) $b
        )+
        linking_table!($($name),+);
    }
}

/// Used for the "prepareClass" shenanigans. I suggest you look up the emojicode docs in order to 
/// figure out what to do here.
/// 
/// Example:
/// ```rust
/// prepare_class!(
///     (class, name) {
///         // do stuff here
///     }
/// );
#[macro_export]
macro_rules! prepare_class {
    (($arg1:ident, $arg2:ident) $b:block) => {
        #[no_mangle]
        #[allow(unused_variables)]
        pub unsafe extern "C" fn prepareClass($arg1: *mut Emojicode_Class, $arg2: EmojicodeChar) $b
    }
}

#[macro_export]
macro_rules! linking_table {
    ($($idents:ident),+) => {
        #[no_mangle]
        #[allow(non_upper_case_globals)]
        pub static linkingTable: [Emojicode_FunctionFunctionPointer; count_args_space!($($idents)*) +1] = [None, $(Some($idents)),+];
    }
}

#[macro_export]
macro_rules! count_args_space {
    ($name:ident) => { 1 };
    ($first:ident $($rest:ident) *) => {
        1 + count_args_space!($($rest) *)
    }
}

/// Converts Rust types to Emojicode Values. Useful for example for returning things from a 
/// function.
pub trait ToValue {
    fn to_value(self) -> Option<Emojicode_Value>;
}

pub trait FromValue<T> {
    fn from_value(self) -> T;
}

impl FromValue<String> for Emojicode_Value {
    fn from_value(self) -> String {
        unsafe {
            let obj_ptr = &emojicode_sys::Emojicode_stringToCString(
                self.object
            );
            CStr::from_ptr(*obj_ptr).to_string_lossy().into_owned()
        }
    }
}

impl ToValue for String {
    fn to_value(self) -> Option<Emojicode_Value> {
        let the_string = CString::new(self);
        match the_string {
            Ok(c) => unsafe {
                Some(Emojicode_Value {
                    object: Emojicode_stringFromChar(c.as_ptr()),
                })
            },
            Err(_) => None,
        }
    }
}

impl ToValue for *mut Emojicode_Object {
    fn to_value(self) -> Option<Emojicode_Value> {
        Some(Emojicode_Value { object: self })
    }
}

pub trait EmojicodeThreadImpl {
    unsafe fn return_from_function(self);
    unsafe fn return_from_function_with_value(self, value: Emojicode_Value);
    //unsafe fn variableDestination(self, index: usize) -> Emojicode_Value;
    unsafe fn variable(self, index: usize) -> Emojicode_Value;
    unsafe fn this_object(self) -> *mut Emojicode_Object;
}

impl EmojicodeThreadImpl for *mut Emojicode_Thread {
    unsafe fn return_from_function(self) {
        let p: *mut u32 = ptr::null_mut();
        (*(*self).stack_).executionPointer = p;
    }

    unsafe fn return_from_function_with_value(self, value: Emojicode_Value) {
        *(*(*self).stack_).destination = value;
        self.return_from_function();
    }

    unsafe fn variable(self, index: usize) -> Emojicode_Value {
        let pt: *const Emojicode_Value = &(*(*self).stack_).thisContext;
        *pt.add(index + 1) as Emojicode_Value
    }

    unsafe fn this_object(self) -> *mut Emojicode_Object {
        (*(*self).stack_).thisContext.object
    }

/*    unsafe fn variableDestination(self, index: usize) -> Emojicode_Value {
        (*(*self).stack_).variableDestination(index)
    }*/

}

pub trait EmojicodeObjectImpl {
    unsafe fn value<T>(self) -> *mut T;
}

impl EmojicodeObjectImpl for *mut Emojicode_Object {
    unsafe fn value<T>(self) -> *mut T {
        self.add(1) as *mut T
    }
}