<commit_before>//! Rust high level bindings for [IUP][1] -- A Portable User Interface Toolkit
//!
//! [1]: http://www.tecgraf.puc-rio.br/iup/
//!
//! The functions in this crate are a thin wrapper around the IUP functions unless noted
//! otherwise. Refer to the IUP website for their full documentation.
//!

extern crate libc;
extern crate "iup-sys" as sys;

use std::ffi::CString;
use std::mem;
use std::ptr;
use std::slice::SliceExt;
use libc::{c_char, c_int};

pub use sys::CallbackReturn;
pub use sys::Ihandle as IhandleRaw;

pub type IupResult = Result<(), String>;

unsafe fn vec_to_c_array(v: Vec<Ihandle>) -> *mut *mut sys::Ihandle {
    let mut raw_v = Vec::with_capacity(v.len());
    for ih in v {
        raw_v.push(ih.ptr);
    }
    let null : *const sys::Ihandle = ptr::null();
    raw_v.push(mem::transmute(null));
    raw_v.as_mut_ptr()
}

#[allow(missing_copy_implementations)]
pub struct Ihandle {
    ptr: *mut sys::Ihandle,
}

impl Ihandle {
    pub fn from_ptr(ih: *mut sys::Ihandle) -> Ihandle {
        if ih.is_null() {
            panic!("Failed to create Ihandle.")
        } else {
            Ihandle { ptr: ih }
        }
    }
}

/// Initializes the IUP toolkit. Must be called before any other IUP function.
pub fn open() -> IupResult {
    let p1 : *const c_int = ptr::null();
    let p2 : *const *const *const c_char = ptr::null();

    match unsafe { sys::IupOpen(p1, p2) } {
        sys::IUP_NOERROR => Ok(()),
        sys::IUP_OPENED => Err("IUP_OPENED: iup::open called while already open.".to_string()),
        sys::IUP_ERROR => Err("IUP_ERROR: X-Windows is not initialized".to_string()),
        _ => unreachable!(),
    }
}

pub fn close() {
    unsafe { sys::IupClose(); }
}

pub fn main_loop() {
    let ok = unsafe { sys::IupMainLoop() };
    assert_eq!(ok, sys::IUP_NOERROR);
}

pub fn show(ih: &mut Ihandle) -> IupResult {
    match unsafe { sys::IupShow(ih.ptr) } {
        sys::IUP_NOERROR => Ok(()),
        sys::IUP_ERROR => Err("IUP_ERROR: unknown error".to_string()),
        _ => unreachable!(),
    }
}

pub fn set_str_attribute(ih: &mut Ihandle, name: &str, value: &str) {
    let name_c = CString::from_slice(name.as_bytes());
    let value_c = CString::from_slice(value.as_bytes());
    unsafe { sys::IupSetStrAttribute(ih.ptr, name_c.as_ptr(), value_c.as_ptr()); }
}

pub fn set_callback(ih: &mut Ihandle, name: &str, callback: sys::Icallback) -> sys::Icallback {
    let name_c = CString::from_slice(name.as_bytes());
    unsafe { sys::IupSetCallback(ih.ptr, name_c.as_ptr(), callback) }
}

pub fn destroy(ih: Ihandle) {
    unsafe { sys::IupDestroy(ih.ptr); }
}

pub fn hboxv(elements: Vec<Ihandle>) -> Ihandle {
    unsafe { Ihandle::from_ptr(sys::IupHboxv(vec_to_c_array(elements))) }
}

pub fn vboxv(elements: Vec<Ihandle>) -> Ihandle {
    unsafe { Ihandle::from_ptr(sys::IupVboxv(vec_to_c_array(elements))) }
}

// Elements

pub fn label(text: &str) -> Ihandle {
    let text_c = CString::from_slice(text.as_bytes());
    unsafe { Ihandle::from_ptr(sys::IupLabel(text_c.as_ptr())) }
}

pub fn dialog(ih: Ihandle) -> Ihandle {
    unsafe { Ihandle::from_ptr(sys::IupDialog(ih.ptr)) }
}

pub fn button(text: &str) -> Ihandle {
    let text_c = CString::from_slice(text.as_bytes());
    let action: *const c_char = ptr::null();
    unsafe { Ihandle::from_ptr(sys::IupButton(text_c.as_ptr(), action)) }
}

pub fn text() -> Ihandle {
    let action: *const c_char = ptr::null();
    unsafe { Ihandle::from_ptr(sys::IupText(action)) }
}
<commit_msg>add function stubs from iup-sys to iup<commit_after>//! Rust high level bindings for [IUP][1] -- A Portable User Interface Toolkit
//!
//! [1]: http://www.tecgraf.puc-rio.br/iup/
//!
//! The functions in this crate are a thin wrapper around the IUP functions unless noted
//! otherwise. Refer to the IUP website for their full documentation.
//!

extern crate libc;
extern crate "iup-sys" as sys;

use std::ffi::CString;
use std::mem;
use std::ptr;
use std::slice::SliceExt;
use libc::{c_char, c_int};

pub use sys::CallbackReturn;
pub use sys::Ihandle as IhandleRaw;

pub type IupResult = Result<(), String>;

unsafe fn vec_to_c_array(v: Vec<Ihandle>) -> *mut *mut sys::Ihandle {
    let mut raw_v = Vec::with_capacity(v.len());
    for ih in v {
        raw_v.push(ih.ptr);
    }
    let null : *const sys::Ihandle = ptr::null();
    raw_v.push(mem::transmute(null));
    raw_v.as_mut_ptr()
}

#[allow(missing_copy_implementations)]
pub struct Ihandle {
    ptr: *mut sys::Ihandle,
}

impl Ihandle {
    pub fn from_ptr(ih: *mut sys::Ihandle) -> Ihandle {
        if ih.is_null() {
            panic!("Failed to create Ihandle.")
        } else {
            Ihandle { ptr: ih }
        }
    }
}

/************************************************************************/
/*                        Main API                                      */
/************************************************************************/

pub fn open() -> IupResult {
    let p1 : *const c_int = ptr::null();
    let p2 : *const *const *const c_char = ptr::null();

    match unsafe { sys::IupOpen(p1, p2) } {
        sys::IUP_NOERROR => Ok(()),
        sys::IUP_OPENED => Err("IUP_OPENED: iup::open called while already open.".to_string()),
        sys::IUP_ERROR => Err("IUP_ERROR: X-Windows is not initialized".to_string()),
        _ => unreachable!(),
    }
}

pub fn close() {
    unsafe { sys::IupClose(); }
}

// pub fn IupImageLibOpen();

pub fn main_loop() {
    let ok = unsafe { sys::IupMainLoop() };
    assert_eq!(ok, sys::IUP_NOERROR);
}

// pub fn IupLoopStep() -> c_int;
// pub fn IupLoopStepWait() -> c_int;
// pub fn IupMainLoopLevel() -> c_int;
// pub fn IupFlush();
// pub fn IupExitLoop();

// pub fn IupRecordInput(filename: *const c_char, mode: c_int) -> c_int;
// pub fn IupPlayInput(filename: *const c_char) -> c_int;

// pub fn IupUpdate(ih: *mut Ihandle);
// pub fn IupUpdateChildren(ih: *mut Ihandle);
// pub fn IupRedraw(ih: *mut Ihandle, children: c_int);
// pub fn IupRefresh(ih: *mut Ihandle);
// pub fn IupRefreshChildren(ih: *mut Ihandle);

// pub fn IupHelp(url: *const c_char) -> c_int;
// pub fn IupLoad(filename: *const c_char) -> *mut c_char;
// pub fn IupLoadBuffer(buffer: *const c_char) -> *mut c_char;

// pub fn IupVersion() -> *mut c_char;
// pub fn IupVersionDate() -> *mut c_char;
// pub fn IupVersionNumber() -> c_int;

// pub fn IupSetLanguage(lng: *const c_char);
// pub fn IupGetLanguage() -> *mut c_char;
// pub fn IupSetLanguageString(name: *const c_char, str: *const c_char);
// pub fn IupStoreLanguageString(name: *const c_char, str: *const c_char);
// pub fn IupGetLanguageString(name: *const c_char) -> *mut c_char;
// pub fn IupSetLanguagePack(ih: *mut Ihandle);

pub fn destroy(ih: Ihandle) {
    unsafe { sys::IupDestroy(ih.ptr); }
}

// pub fn IupDetach(child: *mut Ihandle);
// pub fn IupAppend(ih: *mut Ihandle, child: *mut Ihandle) -> *mut Ihandle;
// pub fn IupInsert(ih: *mut Ihandle, ref_child: *mut Ihandle, child: *mut Ihandle) -> *mut Ihandle;
// pub fn IupGetChild(ih: *mut Ihandle, pos: c_int) -> *mut Ihandle;
// pub fn IupGetChildPos(ih: *mut Ihandle, child: *mut Ihandle) -> c_int;
// pub fn IupGetChildCount(ih: *mut Ihandle) -> c_int;
// pub fn IupGetNextChild(ih: *mut Ihandle, child: *mut Ihandle) -> *mut Ihandle;
// pub fn IupGetBrother(ih: *mut Ihandle) -> *mut Ihandle;
// pub fn IupGetParent(ih: *mut Ihandle) -> *mut Ihandle;
// pub fn IupGetDialog(ih: *mut Ihandle) -> *mut Ihandle;
// pub fn IupGetDialogChild(ih: *mut Ihandle, name: *const c_char) -> *mut Ihandle;
// pub fn IupReparent(ih: *mut Ihandle, new_parent: *mut Ihandle, ref_child: *mut Ihandle) -> c_int;

// pub fn IupPopup(ih: *mut Ihandle, x: c_int, y: c_int) -> c_int;

pub fn show(ih: &mut Ihandle) -> IupResult {
    match unsafe { sys::IupShow(ih.ptr) } {
        sys::IUP_NOERROR => Ok(()),
        sys::IUP_ERROR => Err("IUP_ERROR: unknown error".to_string()),
        _ => unreachable!(),
    }
}

// pub fn IupShowXY(ih: *mut Ihandle, x: c_int, y: c_int) -> c_int;
// pub fn IupHide(ih: *mut Ihandle) -> c_int;
// pub fn IupMap(ih: *mut Ihandle) -> c_int;
// pub fn IupUnmap(ih: *mut Ihandle);

// pub fn IupResetAttribute(ih: *mut Ihandle, name: *const c_char);
// pub fn IupGetAllAttributes(ih: *mut Ihandle, names: *mut *mut c_char, n: c_int) -> c_int;
// pub fn IupSetAtt(handle_name: *const c_char, ih: *mut Ihandle, name: *const c_char, ...) -> *mut Ihandle;
// pub fn IupSetAttributes(ih: *mut Ihandle, str: *const c_char) -> *mut Ihandle;
// pub fn IupGetAttributes(ih: *mut Ihandle) -> *mut c_char;

// pub fn IupSetAttribute(ih: *mut Ihandle, name: *const c_char, value: *const c_char);

pub fn set_str_attribute(ih: &mut Ihandle, name: &str, value: &str) {
    let name_c = CString::from_slice(name.as_bytes());
    let value_c = CString::from_slice(value.as_bytes());
    unsafe { sys::IupSetStrAttribute(ih.ptr, name_c.as_ptr(), value_c.as_ptr()); }
}

// pub fn IupSetStrf(ih: *mut Ihandle, name: *const c_char, format: *const c_char, ...);
// pub fn IupSetInt(ih: *mut Ihandle, name: *const c_char, value: c_int);
// pub fn IupSetFloat(ih: *mut Ihandle, name: *const c_char, value: c_float);
// pub fn IupSetDouble(ih: *mut Ihandle, name: *const c_char, value: c_double);
// pub fn IupSetRGB(ih: *mut Ihandle, name: *const c_char, r: c_uchar, g: c_uchar, b: c_uchar);

// pub fn IupGetAttribute(ih: *mut Ihandle, name: *const c_char) -> *mut c_char;
// pub fn IupGetInt(ih: *mut Ihandle, name: *const c_char) -> c_int;
// pub fn IupGetInt2(ih: *mut Ihandle, name: *const c_char) -> c_int;
// pub fn IupGetIntInt(ih: *mut Ihandle, name: *const c_char, i1: *mut c_int, i2: *mut c_int) -> c_int;
// pub fn IupGetFloat(ih: *mut Ihandle, name: *const c_char) -> c_float;
// pub fn IupGetDouble(ih: *mut Ihandle, name: *const c_char) -> c_double;
// pub fn IupGetRGB(ih: *mut Ihandle, name: *const c_char, r: *mut c_uchar, g: *mut c_uchar, b: *mut c_uchar);
// pub fn IupSetAttributeId(ih: *mut Ihandle, name: *const c_char, id: c_int, value: *const c_char);
// pub fn IupSetStrAttributeId(ih: *mut Ihandle, name: *const c_char, id: c_int, value: *const c_char);
// pub fn IupSetStrfId(ih: *mut Ihandle, name: *const c_char, id: c_int, format: *const c_char, ...);
// pub fn IupSetIntId(ih: *mut Ihandle, name: *const c_char, id: c_int, value: c_int);
// pub fn IupSetFloatId(ih: *mut Ihandle, name: *const c_char, id: c_int, value: c_float);
// pub fn IupSetDoubleId(ih: *mut Ihandle, name: *const c_char, id: c_int, value: c_double);
// pub fn IupSetRGBId(ih: *mut Ihandle, name: *const c_char, id: c_int, r: c_uchar, g: c_uchar, b: c_uchar);

// pub fn IupGetAttributeId(ih: *mut Ihandle, name: *const c_char, id: c_int) -> *mut c_char;
// pub fn IupGetIntId(ih: *mut Ihandle, name: *const c_char, id: c_int) -> c_int;
// pub fn IupGetFloatId(ih: *mut Ihandle, name: *const c_char, id: c_int) -> c_float;
// pub fn IupGetDoubleId(ih: *mut Ihandle, name: *const c_char, id: c_int) -> c_double;
// pub fn IupGetRGBId(ih: *mut Ihandle, name: *const c_char, id: c_int, r: *mut c_uchar, g: *mut c_uchar, b: *mut c_uchar);

// pub fn IupSetAttributeId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, value: *const c_char);
// pub fn IupSetStrAttributeId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, value: *const c_char);
// pub fn IupSetStrfId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, format: *const c_char, ...);
// pub fn IupSetIntId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, value: c_int);
// pub fn IupSetFloatId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, value: c_float);
// pub fn IupSetDoubleId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, value: c_double);
// pub fn IupSetRGBId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, r: c_uchar, g: c_uchar, b: c_uchar);

// pub fn IupGetAttributeId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int) -> *mut c_char;
// pub fn IupGetIntId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int) -> c_int;
// pub fn IupGetFloatId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int) -> c_float;
// pub fn IupGetDoubleId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int) -> c_double;
// pub fn IupGetRGBId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, r: *mut c_uchar, g: *mut c_uchar, b: *mut c_uchar);

// pub fn IupSetGlobal(name: *const c_char, value: *const c_char);
// pub fn IupSetStrGlobal(name: *const c_char, value: *const c_char);
// pub fn IupGetGlobal(name: *const c_char) -> *mut c_char;

// pub fn IupSetFocus(ih: *mut Ihandle) -> *mut Ihandle;
// pub fn IupGetFocus() -> *mut Ihandle;
// pub fn IupPreviousField(ih: *mut Ihandle) -> *mut Ihandle;
// pub fn IupNextField(ih: *mut Ihandle) -> *mut Ihandle;

// pub fn IupGetCallback(ih: *mut Ihandle, name: *const c_char) -> Icallback;

pub fn set_callback(ih: &mut Ihandle, name: &str, callback: sys::Icallback) -> sys::Icallback {
    let name_c = CString::from_slice(name.as_bytes());
    unsafe { sys::IupSetCallback(ih.ptr, name_c.as_ptr(), callback) }
}

// pub fn IupSetCallbacks(ih: *mut Ihandle, name: *const c_char, func: Icallback, ...) -> *mut Ihandle;

// pub fn IupGetFunction(name: *const c_char) -> Icallback;
// pub fn IupSetFunction(name: *const c_char, func: Icallback) -> Icallback;

// pub fn IupGetHandle(name: *const c_char) -> *mut Ihandle;
// pub fn IupSetHandle(name: *const c_char, ih: *mut Ihandle) -> *mut Ihandle;
// pub fn IupGetAllNames(names: *mut *mut c_char, n: c_int) -> c_int;
// pub fn IupGetAllDialogs(names: *mut *mut c_char, n: c_int) -> c_int;
// pub fn IupGetName(ih: *mut Ihandle) -> *mut c_char;

// pub fn IupSetAttributeHandle(ih: *mut Ihandle, name: *const c_char, ih_named: *mut Ihandle);
// pub fn IupGetAttributeHandle(ih: *mut Ihandle, name: *const c_char) -> *mut Ihandle;

// pub fn IupGetClassName(ih: *mut Ihandle) -> *mut c_char;
// pub fn IupGetClassType(ih: *mut Ihandle) -> *mut c_char;
// pub fn IupGetAllClasses(names: *mut *mut c_char, n: c_int) -> c_int;
// pub fn IupGetClassAttributes(classname: *const c_char, names: *mut *mut c_char, n: c_int) -> c_int;
// pub fn IupGetClassCallbacks(classname: *const c_char, names: *mut *mut c_char, n: c_int) -> c_int;
// pub fn IupSaveClassAttributes(ih: *mut Ihandle);
// pub fn IupCopyClassAttributes(src_ih: *mut Ihandle, dst_ih: *mut Ihandle);
// pub fn IupSetClassDefaultAttribute(classname: *const c_char, name: *const c_char, value: *const c_char);
// pub fn IupClassMatch(ih: *mut Ihandle, classname: *const c_char) -> c_int;

// pub fn IupCreate(classname: *const c_char) -> *mut Ihandle;
// pub fn IupCreatev(classname: *const c_char, params: *mut *mut c_void) -> *mut Ihandle;
// pub fn IupCreatep(classname: *const c_char, first: *mut c_void, ...) -> *mut Ihandle;

/************************************************************************/
/*                        Elements                                      */
/************************************************************************/
// pub fn IupFill() -> *mut Ihandle;
// pub fn IupRadio(child: *mut Ihandle) -> *mut Ihandle;
// pub fn IupVbox(child: *mut Ihandle, ...) -> *mut Ihandle;

pub fn vboxv(elements: Vec<Ihandle>) -> Ihandle {
    unsafe { Ihandle::from_ptr(sys::IupVboxv(vec_to_c_array(elements))) }
}

// pub fn IupZbox(child: *mut Ihandle, ...) -> *mut Ihandle;
// pub fn IupZboxv(children: *mut *mut Ihandle) -> *mut Ihandle;
// pub fn IupHbox(child: *mut Ihandle, ...) -> *mut Ihandle;

pub fn hboxv(elements: Vec<Ihandle>) -> Ihandle {
    unsafe { Ihandle::from_ptr(sys::IupHboxv(vec_to_c_array(elements))) }
}

// pub fn IupNormalizer(ih_first: *mut Ihandle, ...) -> *mut Ihandle;
// pub fn IupNormalizerv(ih_list: *mut *mut Ihandle) -> *mut Ihandle;

// pub fn IupCbox(child: *mut Ihandle, ...) -> *mut Ihandle;
// pub fn IupCboxv(children: *mut *mut Ihandle) -> *mut Ihandle;
// pub fn IupSbox(child: *mut Ihandle) -> *mut Ihandle;
// pub fn IupSplit(child1: *mut Ihandle, child2: *mut Ihandle) -> *mut Ihandle;
// pub fn IupScrollBox(child: *mut Ihandle) -> *mut Ihandle;
// pub fn IupGridBox(child: *mut Ihandle, ...) -> *mut Ihandle;
// pub fn IupGridBoxv(children: *mut *mut Ihandle) -> *mut Ihandle;
// pub fn IupExpander(child: *mut Ihandle) -> *mut Ihandle;
// pub fn IupDetachBox(child: *mut Ihandle) -> *mut Ihandle;
// pub fn IupBackgroundBox(child: *mut Ihandle) -> *mut Ihandle;

// pub fn IupFrame(child: *mut Ihandle) -> *mut Ihandle;

// pub fn IupImage(width: c_int, height: c_int, pixmap: *const c_uchar) -> *mut Ihandle;
// pub fn IupImageRGB(width: c_int, height: c_int, pixmap: *const c_uchar) -> *mut Ihandle;
// pub fn IupImageRGBA(width: c_int, height: c_int, pixmap: *const c_uchar) -> *mut Ihandle;

// pub fn IupItem(title: *const c_char, action: *const c_char) -> *mut Ihandle;
// pub fn IupSubmenu(title: *const c_char, child: *mut Ihandle) -> *mut Ihandle;
// pub fn IupSeparator() -> *mut Ihandle;
// pub fn IupMenu(child: *mut Ihandle, ...) -> *mut Ihandle;
// pub fn IupMenuv(children: *mut *mut Ihandle) -> *mut Ihandle;

pub fn button(text: &str) -> Ihandle {
    let text_c = CString::from_slice(text.as_bytes());
    let action: *const c_char = ptr::null();
    unsafe { Ihandle::from_ptr(sys::IupButton(text_c.as_ptr(), action)) }
}

// pub fn IupCanvas(action: *const c_char) -> *mut Ihandle;

pub fn dialog(ih: Ihandle) -> Ihandle {
    unsafe { Ihandle::from_ptr(sys::IupDialog(ih.ptr)) }
}

// pub fn IupUser() -> *mut Ihandle;

pub fn label(text: &str) -> Ihandle {
    let text_c = CString::from_slice(text.as_bytes());
    unsafe { Ihandle::from_ptr(sys::IupLabel(text_c.as_ptr())) }
}

// pub fn IupList(action: *const c_char) -> *mut Ihandle;

pub fn text() -> Ihandle {
    let action: *const c_char = ptr::null();
    unsafe { Ihandle::from_ptr(sys::IupText(action)) }
}

// pub fn IupMultiLine(action: *const c_char) -> *mut Ihandle;
// pub fn IupToggle(title: *const c_char, action: *const c_char) -> *mut Ihandle;
// pub fn IupTimer() -> *mut Ihandle;
// pub fn IupClipboard() -> *mut Ihandle;
// pub fn IupProgressBar() -> *mut Ihandle;
// pub fn IupVal(_type: *const c_char) -> *mut Ihandle;
// pub fn IupTabs(child: *mut Ihandle, ...) -> *mut Ihandle;
// pub fn IupTabsv(children: *mut *mut Ihandle) -> *mut Ihandle;
// pub fn IupTree() -> *mut Ihandle;
// pub fn IupLink(url: *const c_char, title: *const c_char) -> *mut Ihandle;

/************************************************************************/
/*                      Utilities                                       */
/************************************************************************/

/* IupImage utility */
// pub fn IupSaveImageAsText(ih: *mut Ihandle, file_name: *const c_char, format: *const c_char, name: *const c_char) -> c_int;

/* IupText and IupScintilla utilities */
// pub fn IupTextConvertLinColToPos(ih: *mut Ihandle, lin: c_int, col: c_int, pos: *mut c_int);
// pub fn IupTextConvertPosToLinCol(ih: *mut Ihandle, pos: c_int, lin: *mut c_int, col: *mut c_int);

/* IupTree utilities */
// pub fn IupTreeSetUserId(ih: *mut Ihandle, id: c_int, userid: *mut c_void) -> c_int;
// pub fn IupTreeGetUserId(ih: *mut Ihandle, id: c_int) -> *mut c_void;
// pub fn IupTreeGetId(ih: *mut Ihandle, userid: *mut c_void) -> c_int;
// pub fn IupTreeSetAttributeHandle(ih: *mut Ihandle, name: *const c_char, id: c_int, ih_named: *mut Ihandle);

/************************************************************************/
/*                      Pre-definided dialogs                           */
/************************************************************************/
// pub fn IupFileDlg() -> *mut Ihandle;
// pub fn IupMessageDlg() -> *mut Ihandle;
// pub fn IupColorDlg() -> *mut Ihandle;
// pub fn IupFontDlg() -> *mut Ihandle;
// pub fn IupProgressDlg() -> *mut Ihandle;

// pub fn IupGetFile(arq: *mut c_char) -> c_int;
// pub fn IupMessage(title: *const c_char, msg: *const c_char);
// pub fn IupMessagef(title: *const c_char, format: *const c_char, ...);
// pub fn IupAlarm(title: *const c_char, msg: *const c_char, b1: *const c_char, b2: *const c_char, b3: *const c_char) -> c_int;
// pub fn IupScanf(format: *const c_char, ...) -> c_int;
// pub fn IupListDialog(_type: c_int, title: *const c_char, size: c_int, list: *mut *const c_char, op: c_int, max_col: c_int, max_lin: c_int, marks: *mut c_int) -> c_int;
// pub fn IupGetText(title: *const c_char, text: *mut c_char) -> c_int;
// pub fn IupGetColor(x: c_int, y: c_int, r: *mut c_uchar, g: *mut c_uchar, b: *mut c_uchar) -> c_int;

// pub fn IupGetParam(title: *const c_char, action: Iparamcb, user_data: *mut c_void, format: *const c_char, ...) -> c_int;
// pub fn IupGetParamv(title: *const c_char, action: Iparamcb, user_data: *mut c_void, format: *const c_char, param_count: c_int, param_extra: c_int, param_data: *mut *mut c_void) -> c_int;

// pub fn IupLayoutDialog(dialog: *mut Ihandle) -> *mut Ihandle;
// pub fn IupElementPropertiesDialog(elem: *mut Ihandle) -> *mut Ihandle;
<|endoftext|>


<commit_before>use base::{TeardownTree, TeardownTreeInternal, Item, Node};
use slot_stack::SlotStack;

pub trait TraversalDriver<T: Item> {
    #[inline(always)]
    fn decide(&self, key: &T::Key) -> TraversalDecision;
}

#[derive(Clone, Copy, Debug)]
pub struct TraversalDecision {
    pub left: bool,
    pub right: bool,
}

pub struct DeleteRangeCache<T: Item> {
    pub slots_min: SlotStack<T>, pub slots_max: SlotStack<T>,   // TODO: we no longer need both stacks, one is enough... but removing one causes 3% performance regression
}

impl<T: Item> Clone for DeleteRangeCache<T> {
    fn clone(&self) -> Self {
        debug_assert!(self.slots_min.is_empty() && self.slots_max.is_empty());
        let capacity = self.slots_max.capacity;
        DeleteRangeCache::new(capacity)
    }
}

impl<T: Item> DeleteRangeCache<T> {
    pub fn new(height: usize) -> DeleteRangeCache<T> {
        let slots_min = SlotStack::new(height);
        let slots_max = SlotStack::new(height);
        DeleteRangeCache { slots_min: slots_min, slots_max: slots_max }
    }
}

pub struct DeleteRange<'a, T: 'a+Item> {
    tree: &'a mut TeardownTree<T>,
    slots_min: SlotStack<T>, slots_max: SlotStack<T>,
    pub output: &'a mut Vec<T>
}

impl<'a, T: Item> DeleteRange<'a, T> {
    pub fn new(tree: &'a mut TeardownTree<T>, output: &'a mut Vec<T>) -> DeleteRange<'a, T> {
        let cache = tree.delete_range_cache.take().unwrap();
        DeleteRange { tree: tree, slots_min: cache.slots_min, slots_max: cache.slots_max, output: output }
    }

    /// The items are not guaranteed to be returned in any particular order.
    pub fn delete_range<D: TraversalDriver<T>>(mut self, drv: &mut D) {
        self.delete_range_loop(drv, 0);
        debug_assert!(self.slots_min.is_empty() && self.slots_max.is_empty() && self.tree.traversal_stack.is_empty());

        self.tree.delete_range_cache = Some(DeleteRangeCache { slots_min: self.slots_min, slots_max: self.slots_max });
    }

    //---- helpers ---------------------------------------------------------------------------------
    #[inline(always)]
    fn node(&self, idx: usize) -> &Node<T> {
        self.tree.node(idx)
    }

    #[inline(always)]
    fn item(&mut self, idx: usize) -> &T {
        &self.node(idx).item
    }

    #[inline(always)]
    fn lefti(idx: usize) -> usize {
        TeardownTree::<T>::lefti(idx)
    }

    #[inline(always)]
    fn righti(idx: usize) -> usize {
        TeardownTree::<T>::righti(idx)
    }

    #[inline(always)]
    fn consume(&mut self, idx: usize) {
        let item = self.tree.take(idx);
        self.output.push(item);
    }
}

// v5
impl<'a, T: Item> DeleteRange<'a, T> {
    #[inline]
    fn delete_range_loop<D: TraversalDriver<T>>(&mut self, drv: &D, mut idx: usize) {
        loop {
            if self.tree.is_null(idx) {
                return;
            }

            let decision = drv.decide(&self.item(idx).key());

            if decision.left && decision.right {
                self.consume(idx);
                let removed = self.descend_delete_left(drv, idx, true);
                self.descend_delete_right(drv, idx, removed);
            } else if decision.left {
                idx = Self::lefti(idx);
            } else {
                debug_assert!(decision.right);
                idx = Self::righti(idx);
            }
        }
    }

    #[inline(never)]
    fn delete_range_min<D: TraversalDriver<T>>(&mut self, drv: &D, idx: usize) {
        let decision = drv.decide(&self.item(idx).key());
        debug_assert!(decision.left);

        if decision.right {
            // the root and the whole left subtree are inside the range
            self.consume(idx);
            self.consume_subtree(Self::lefti(idx));
            self.descend_delete_right(drv, idx, true);
        } else {
            // the root and the right subtree are outside the range
            self.descend_left(idx,
                   |this: &mut Self, child_idx| this.delete_range_min(drv, child_idx)
            );

            if self.slots_min.has_open() {
                self.slots_min.fill(self.tree.take(idx));
                self.descend_fill_right(idx);
            }
        }
    }

    #[inline(never)]
    fn delete_range_max<D: TraversalDriver<T>>(&mut self, drv: &D, idx: usize) {
        let decision = drv.decide(&self.item(idx).key());
        debug_assert!(decision.right);

        if decision.left {
            // the root and the whole right subtree are inside the range
            self.consume(idx);
            self.consume_subtree(Self::righti(idx));
            self.descend_delete_left(drv, idx, true);
        } else {
            // the root and the left subtree are outside the range
            self.descend_right(idx,
                   |this: &mut Self, child_idx| this.delete_range_max(drv, child_idx)
            );

            if self.slots_max.has_open() {
                self.slots_max.fill(self.tree.take(idx));
                self.descend_fill_left(idx);
            }
        }
    }

    //---- delete_subtree_* ---------------------------------------------------------------
    #[inline]
    fn consume_subtree(&mut self, root: usize) {
        debug_assert!(self.tree.traversal_stack.is_empty());

        self.tree.traverse_preorder(root, self.output, |tree, output, idx| {
            unsafe {
                let len = output.len();
                debug_assert!(len < output.capacity());
                let p = output.as_mut_ptr().offset(len as isize);
                output.set_len(len + 1);
                tree.move_to(idx, p)
            }
        });
    }

    //---- fill_slots_* -------------------------------------------------------------------
    #[inline(never)]
    fn fill_slots_min(&mut self, idx: usize) -> bool {
        if self.tree.is_null(idx) {
            return false;
        }

        let done = self.fill_slots_min(Self::lefti(idx));

        if done {
            true
        } else {
            debug_assert!(self.slots_min.has_open());

            let item = self.tree.take(idx);
            self.slots_min.fill(item);

            self.descend_fill_right(idx);

            let done = !self.tree.is_null(idx);
            if done {
                true
            } else {
                !self.slots_min.has_open()
            }
        }
    }

    #[inline(never)]
    fn fill_slots_max(&mut self, idx: usize) -> bool {
        if self.tree.is_null(idx) {
            return false;
        }

        let done = self.fill_slots_max(Self::righti(idx));

        if done {
            true
        } else {
            debug_assert!(self.slots_max.has_open());

            let item = self.tree.take(idx);
            self.slots_max.fill(item);

            self.descend_fill_left(idx);

            let done = !self.tree.is_null(idx);
            if done {
                true
            } else {
                !self.slots_max.has_open()
            }
        }
    }

    //---- descend_* -------------------------------------------------------------------------------

    #[inline(always)]
    fn descend_left<F>(&mut self, idx: usize, f: F)
        where F: Fn(&mut Self, usize) {
        let child_idx = Self::lefti(idx);
        if !self.tree.is_null(child_idx) {
            f(self, child_idx);
        }
    }

    #[inline(always)]
    fn descend_right<F>(&mut self, idx: usize, f: F)
        where F: Fn(&mut Self, usize) {
        let child_idx = Self::righti(idx);
        if !self.tree.is_null(child_idx) {
            f(self, child_idx);
        }
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_left_with_slot<F>(&mut self, idx: usize, f: F) -> bool
                                                        where F: Fn(&mut Self, usize) {
        debug_assert!(self.tree.is_null(idx));

        let child_idx = Self::lefti(idx);
        if self.tree.is_null(child_idx) {
            return true;
        }

        self.slots_max.push();

        f(self, child_idx);

        let slot = self.slots_max.pop();

        if let Some(item) = slot {
            debug_assert!(self.tree.is_null(idx));
            self.tree.place(idx, item);
            false
        } else {
            true
        }
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_right_with_slot<F>(&mut self, idx: usize, f: F) -> bool
                                                        where F: Fn(&mut Self, usize) {
        debug_assert!(self.tree.is_null(idx));

        let child_idx = Self::righti(idx);
        if self.tree.is_null(child_idx) {
            return true;
        }

        self.slots_min.push();

        f(self, child_idx);

        let slot = self.slots_min.pop();

        if let Some(item) = slot {
            debug_assert!(self.tree.is_null(idx));
            self.tree.place(idx, item);
            false
        } else {
            true
        }
    }

    #[inline(always)]
    fn descend_fill_left(&mut self, idx: usize) {
        self.descend_left_with_slot(idx, |this: &mut Self, child_idx| {
            this.fill_slots_max(child_idx);
        });
    }

    #[inline(always)]
    fn descend_fill_right(&mut self, idx: usize) {
        self.descend_right_with_slot(idx, |this: &mut Self, child_idx| {
            this.fill_slots_min(child_idx);
        });
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_delete_left<D: TraversalDriver<T>>(&mut self, drv: &D, idx: usize, with_slot: bool) -> bool {
        if with_slot {
            self.descend_left_with_slot(idx,
                        |this: &mut Self, child_idx| this.delete_range_max(drv, child_idx)
            )
        } else {
            self.descend_left(idx,
                        |this: &mut Self, child_idx| this.delete_range_max(drv, child_idx)
            );

            false
        }
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_delete_right<D: TraversalDriver<T>>(&mut self, drv: &D, idx: usize, with_slot: bool) -> bool {
        if with_slot {
            self.descend_right_with_slot(idx,
                        |this: &mut Self, child_idx| this.delete_range_min(drv, child_idx)
            )
        } else {
            self.descend_right(idx,
                        |this: &mut Self, child_idx| this.delete_range_min(drv, child_idx)
            );

            false
        }
    }
}
<commit_msg>early return from delete_range_loop (though it seems to work fine without!)<commit_after>use base::{TeardownTree, TeardownTreeInternal, Item, Node};
use slot_stack::SlotStack;

pub trait TraversalDriver<T: Item> {
    #[inline(always)]
    fn decide(&self, key: &T::Key) -> TraversalDecision;
}

#[derive(Clone, Copy, Debug)]
pub struct TraversalDecision {
    pub left: bool,
    pub right: bool,
}

pub struct DeleteRangeCache<T: Item> {
    pub slots_min: SlotStack<T>, pub slots_max: SlotStack<T>,   // TODO: we no longer need both stacks, one is enough... but removing one causes 3% performance regression
}

impl<T: Item> Clone for DeleteRangeCache<T> {
    fn clone(&self) -> Self {
        debug_assert!(self.slots_min.is_empty() && self.slots_max.is_empty());
        let capacity = self.slots_max.capacity;
        DeleteRangeCache::new(capacity)
    }
}

impl<T: Item> DeleteRangeCache<T> {
    pub fn new(height: usize) -> DeleteRangeCache<T> {
        let slots_min = SlotStack::new(height);
        let slots_max = SlotStack::new(height);
        DeleteRangeCache { slots_min: slots_min, slots_max: slots_max }
    }
}

pub struct DeleteRange<'a, T: 'a+Item> {
    tree: &'a mut TeardownTree<T>,
    slots_min: SlotStack<T>, slots_max: SlotStack<T>,
    pub output: &'a mut Vec<T>
}

impl<'a, T: Item> DeleteRange<'a, T> {
    pub fn new(tree: &'a mut TeardownTree<T>, output: &'a mut Vec<T>) -> DeleteRange<'a, T> {
        let cache = tree.delete_range_cache.take().unwrap();
        DeleteRange { tree: tree, slots_min: cache.slots_min, slots_max: cache.slots_max, output: output }
    }

    /// The items are not guaranteed to be returned in any particular order.
    pub fn delete_range<D: TraversalDriver<T>>(mut self, drv: &mut D) {
        self.delete_range_loop(drv, 0);
        debug_assert!(self.slots_min.is_empty() && self.slots_max.is_empty() && self.tree.traversal_stack.is_empty());

        self.tree.delete_range_cache = Some(DeleteRangeCache { slots_min: self.slots_min, slots_max: self.slots_max });
    }

    //---- helpers ---------------------------------------------------------------------------------
    #[inline(always)]
    fn node(&self, idx: usize) -> &Node<T> {
        self.tree.node(idx)
    }

    #[inline(always)]
    fn item(&mut self, idx: usize) -> &T {
        &self.node(idx).item
    }

    #[inline(always)]
    fn lefti(idx: usize) -> usize {
        TeardownTree::<T>::lefti(idx)
    }

    #[inline(always)]
    fn righti(idx: usize) -> usize {
        TeardownTree::<T>::righti(idx)
    }

    #[inline(always)]
    fn consume(&mut self, idx: usize) {
        let item = self.tree.take(idx);
        self.output.push(item);
    }
}

// v5
impl<'a, T: Item> DeleteRange<'a, T> {
    #[inline]
    fn delete_range_loop<D: TraversalDriver<T>>(&mut self, drv: &D, mut idx: usize) {
        loop {
            if self.tree.is_null(idx) {
                return;
            }

            let decision = drv.decide(&self.item(idx).key());

            if decision.left && decision.right {
                self.consume(idx);
                let removed = self.descend_delete_left(drv, idx, true);
                self.descend_delete_right(drv, idx, removed);
                return;
            } else if decision.left {
                idx = Self::lefti(idx);
            } else {
                debug_assert!(decision.right);
                idx = Self::righti(idx);
            }
        }
    }

    #[inline(never)]
    fn delete_range_min<D: TraversalDriver<T>>(&mut self, drv: &D, idx: usize) {
        let decision = drv.decide(&self.item(idx).key());
        debug_assert!(decision.left);

        if decision.right {
            // the root and the whole left subtree are inside the range
            self.consume(idx);
            self.consume_subtree(Self::lefti(idx));
            self.descend_delete_right(drv, idx, true);
        } else {
            // the root and the right subtree are outside the range
            self.descend_left(idx,
                   |this: &mut Self, child_idx| this.delete_range_min(drv, child_idx)
            );

            if self.slots_min.has_open() {
                self.slots_min.fill(self.tree.take(idx));
                self.descend_fill_right(idx);
            }
        }
    }

    #[inline(never)]
    fn delete_range_max<D: TraversalDriver<T>>(&mut self, drv: &D, idx: usize) {
        let decision = drv.decide(&self.item(idx).key());
        debug_assert!(decision.right);

        if decision.left {
            // the root and the whole right subtree are inside the range
            self.consume(idx);
            self.consume_subtree(Self::righti(idx));
            self.descend_delete_left(drv, idx, true);
        } else {
            // the root and the left subtree are outside the range
            self.descend_right(idx,
                   |this: &mut Self, child_idx| this.delete_range_max(drv, child_idx)
            );

            if self.slots_max.has_open() {
                self.slots_max.fill(self.tree.take(idx));
                self.descend_fill_left(idx);
            }
        }
    }

    //---- delete_subtree_* ---------------------------------------------------------------
    #[inline]
    fn consume_subtree(&mut self, root: usize) {
        debug_assert!(self.tree.traversal_stack.is_empty());

        self.tree.traverse_preorder(root, self.output, |tree, output, idx| {
            unsafe {
                let len = output.len();
                debug_assert!(len < output.capacity());
                let p = output.as_mut_ptr().offset(len as isize);
                output.set_len(len + 1);
                tree.move_to(idx, p)
            }
        });
    }

    //---- fill_slots_* -------------------------------------------------------------------
    #[inline(never)]
    fn fill_slots_min(&mut self, idx: usize) -> bool {
        if self.tree.is_null(idx) {
            return false;
        }

        let done = self.fill_slots_min(Self::lefti(idx));

        if done {
            true
        } else {
            debug_assert!(self.slots_min.has_open());

            let item = self.tree.take(idx);
            self.slots_min.fill(item);

            self.descend_fill_right(idx);

            let done = !self.tree.is_null(idx);
            if done {
                true
            } else {
                !self.slots_min.has_open()
            }
        }
    }

    #[inline(never)]
    fn fill_slots_max(&mut self, idx: usize) -> bool {
        if self.tree.is_null(idx) {
            return false;
        }

        let done = self.fill_slots_max(Self::righti(idx));

        if done {
            true
        } else {
            debug_assert!(self.slots_max.has_open());

            let item = self.tree.take(idx);
            self.slots_max.fill(item);

            self.descend_fill_left(idx);

            let done = !self.tree.is_null(idx);
            if done {
                true
            } else {
                !self.slots_max.has_open()
            }
        }
    }

    //---- descend_* -------------------------------------------------------------------------------

    #[inline(always)]
    fn descend_left<F>(&mut self, idx: usize, f: F)
        where F: Fn(&mut Self, usize) {
        let child_idx = Self::lefti(idx);
        if !self.tree.is_null(child_idx) {
            f(self, child_idx);
        }
    }

    #[inline(always)]
    fn descend_right<F>(&mut self, idx: usize, f: F)
        where F: Fn(&mut Self, usize) {
        let child_idx = Self::righti(idx);
        if !self.tree.is_null(child_idx) {
            f(self, child_idx);
        }
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_left_with_slot<F>(&mut self, idx: usize, f: F) -> bool
                                                        where F: Fn(&mut Self, usize) {
        debug_assert!(self.tree.is_null(idx));

        let child_idx = Self::lefti(idx);
        if self.tree.is_null(child_idx) {
            return true;
        }

        self.slots_max.push();

        f(self, child_idx);

        let slot = self.slots_max.pop();

        if let Some(item) = slot {
            debug_assert!(self.tree.is_null(idx));
            self.tree.place(idx, item);
            false
        } else {
            true
        }
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_right_with_slot<F>(&mut self, idx: usize, f: F) -> bool
                                                        where F: Fn(&mut Self, usize) {
        debug_assert!(self.tree.is_null(idx));

        let child_idx = Self::righti(idx);
        if self.tree.is_null(child_idx) {
            return true;
        }

        self.slots_min.push();

        f(self, child_idx);

        let slot = self.slots_min.pop();

        if let Some(item) = slot {
            debug_assert!(self.tree.is_null(idx));
            self.tree.place(idx, item);
            false
        } else {
            true
        }
    }

    #[inline(always)]
    fn descend_fill_left(&mut self, idx: usize) {
        self.descend_left_with_slot(idx, |this: &mut Self, child_idx| {
            this.fill_slots_max(child_idx);
        });
    }

    #[inline(always)]
    fn descend_fill_right(&mut self, idx: usize) {
        self.descend_right_with_slot(idx, |this: &mut Self, child_idx| {
            this.fill_slots_min(child_idx);
        });
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_delete_left<D: TraversalDriver<T>>(&mut self, drv: &D, idx: usize, with_slot: bool) -> bool {
        if with_slot {
            self.descend_left_with_slot(idx,
                        |this: &mut Self, child_idx| this.delete_range_max(drv, child_idx)
            )
        } else {
            self.descend_left(idx,
                        |this: &mut Self, child_idx| this.delete_range_max(drv, child_idx)
            );

            false
        }
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_delete_right<D: TraversalDriver<T>>(&mut self, drv: &D, idx: usize, with_slot: bool) -> bool {
        if with_slot {
            self.descend_right_with_slot(idx,
                        |this: &mut Self, child_idx| this.delete_range_min(drv, child_idx)
            )
        } else {
            self.descend_right(idx,
                        |this: &mut Self, child_idx| this.delete_range_min(drv, child_idx)
            );

            false
        }
    }
}
<|endoftext|>


<commit_before>fn dupli<T: Clone>(list: &[T]) -> ~[T] {
    let mut r = ~[];
    for e in list.iter() {
        r.push(e.clone());
        r.push(e.clone());
    }
    r
}

fn main() {
    let list = ~['a', 'b', 'c', 'c', 'd'];
    println!("{:?}", dupli(list));
}

<commit_msg>Cleanup Problem 14<commit_after>// The author of this work hereby waives all claim of copyright (economic and
// moral) in this work and immediately places it in the public domain; it may
// be used, distorted or destroyed in any manner whatsoever without further
// attribution or notice to the creator.

//! Problem 14: Vectors: duplicate
//!
//! Duplicate the elements of a vector.
//!
//! Your function could have this signature:
//! `fn dupli<T: Clone>(vec: ~[T]) -> ~[T]`

fn dupli<T: Clone>(vec: ~[T]) -> ~[T] {
    vec.move_iter().flat_map(|e| Vec::from_elem(2, e).move_iter()).collect()
}

#[test]
fn dupli_test() {
    let vec = ~['a', 'b', 'c', 'c', 'd'];
    assert_eq!(dupli(vec), ~['a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd']);
}
<|endoftext|>


<commit_before>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use base::CGFloat;
use color_space::{CGColorSpace, CGColorSpaceRef};
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use libc::{c_void, size_t};
use std::mem;
use std::ptr;
use std::slice;
use geometry::CGRect;
use image::{CGImage, CGImageRef};

#[repr(C)]
pub enum CGTextDrawingMode {
    CGTextFill,
    CGTextStroke,
    CGTextFillStroke,
    CGTextInvisible,
    CGTextFillClip,
    CGTextStrokeClip,
    CGTextClip
}

#[repr(C)]
pub struct __CGContext;

pub type CGContextRef = *const __CGContext;

pub struct CGContext {
    obj: CGContextRef,
}

impl Drop for CGContext {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.as_CFTypeRef())
        }
    }
}

impl Clone for CGContext {
    fn clone(&self) -> CGContext {
        unsafe {
            TCFType::wrap_under_get_rule(self.as_concrete_TypeRef())
        }
    }
}

impl TCFType<CGContextRef> for CGContext {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CGContextRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CGContextRef) -> CGContext {
        let reference: CGContextRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CGContextRef) -> CGContext {
        CGContext {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CGContextGetTypeID()
        }
    }
}

impl CGContext {
    pub fn create_bitmap_context(width: size_t,
                                 height: size_t,
                                 bits_per_component: size_t,
                                 bytes_per_row: size_t,
                                 space: &CGColorSpace,
                                 bitmap_info: u32)
                                 -> CGContext {
        unsafe {
            let result = CGBitmapContextCreate(ptr::null_mut(),
                                               width,
                                               height,
                                               bits_per_component,
                                               bytes_per_row,
                                               space.as_concrete_TypeRef(),
                                               bitmap_info);
            TCFType::wrap_under_create_rule(result)
        }
    }

    pub fn data(&mut self) -> &mut [u8] {
        unsafe {
            slice::from_raw_parts_mut(
                    CGBitmapContextGetData(self.as_concrete_TypeRef()) as *mut u8,
                    (self.height() * self.bytes_per_row()) as usize)
        }
    }

    pub fn width(&self) -> size_t {
        unsafe {
            CGBitmapContextGetWidth(self.as_concrete_TypeRef())
        }
    }

    pub fn height(&self) -> size_t {
        unsafe {
            CGBitmapContextGetHeight(self.as_concrete_TypeRef())
        }
    }

    pub fn bytes_per_row(&self) -> size_t {
        unsafe {
            CGBitmapContextGetBytesPerRow(self.as_concrete_TypeRef())
        }
    }

    pub fn set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
        unsafe {
            CGContextSetRGBFillColor(self.as_concrete_TypeRef(), red, green, blue, alpha)
        }
    }

    pub fn set_allows_font_smoothing(&self, allows_font_smoothing: bool) {
        unsafe {
            CGContextSetAllowsFontSmoothing(self.as_concrete_TypeRef(), allows_font_smoothing)
        }
    }

    pub fn set_should_smooth_fonts(&self, should_smooth_fonts: bool) {
        unsafe {
            CGContextSetShouldSmoothFonts(self.as_concrete_TypeRef(), should_smooth_fonts)
        }
    }

    pub fn set_allows_antialiasing(&self, allows_antialiasing: bool) {
        unsafe {
            CGContextSetAllowsAntialiasing(self.as_concrete_TypeRef(), allows_antialiasing)
        }
    }

    pub fn set_should_antialias(&self, should_antialias: bool) {
        unsafe {
            CGContextSetShouldAntialias(self.as_concrete_TypeRef(), should_antialias)
        }
    }

    pub fn set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool) {
        unsafe {
            CGContextSetAllowsFontSubpixelQuantization(self.as_concrete_TypeRef(), allows_font_subpixel_quantization)
        }
    }

    pub fn set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool) {
        unsafe {
            CGContextSetShouldSubpixelQuantizeFonts(self.as_concrete_TypeRef(), should_subpixel_quantize_fonts)
        }
    }

    pub fn set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool) {
        unsafe {
            CGContextSetAllowsFontSubpixelPositioning(self.as_concrete_TypeRef(), allows_font_subpixel_positioning)
        }
    }

    pub fn set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool) {
        unsafe {
            CGContextSetShouldSubpixelPositionFonts(self.as_concrete_TypeRef(), should_subpixel_position_fonts)
        }
    }

    pub fn set_text_drawing_mode(&self, mode: CGTextDrawingMode) {
        unsafe {
            CGContextSetTextDrawingMode(self.as_concrete_TypeRef(), mode)
        }
    }

    pub fn fill_rect(&self, rect: CGRect) {
        unsafe {
            CGContextFillRect(self.as_concrete_TypeRef(), rect)
        }
    }

    pub fn draw_image(&self, rect: CGRect, image: &CGImage) {
        unsafe {
            CGContextDrawImage(self.as_concrete_TypeRef(), rect, image.as_concrete_TypeRef());
        }
    }

    pub fn create_image(&self) -> Option<CGImage> {
        let image = unsafe { CGBitmapContextCreateImage(self.as_concrete_TypeRef()) };
        if image != ptr::null() {
            Some(unsafe { CGImage::wrap_under_create_rule(image) })
        } else {
            None
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    fn CGBitmapContextCreate(data: *mut c_void,
                             width: size_t,
                             height: size_t,
                             bitsPerComponent: size_t,
                             bytesPerRow: size_t,
                             space: CGColorSpaceRef,
                             bitmapInfo: u32)
                             -> CGContextRef;
    fn CGBitmapContextGetData(context: CGContextRef) -> *mut c_void;
    fn CGBitmapContextGetWidth(context: CGContextRef) -> size_t;
    fn CGBitmapContextGetHeight(context: CGContextRef) -> size_t;
    fn CGBitmapContextGetBytesPerRow(context: CGContextRef) -> size_t;
    fn CGBitmapContextCreateImage(context: CGContextRef) -> CGImageRef;
    fn CGContextGetTypeID() -> CFTypeID;
    fn CGContextSetAllowsFontSmoothing(c: CGContextRef, allowsFontSmoothing: bool);
    fn CGContextSetShouldSmoothFonts(c: CGContextRef, shouldSmoothFonts: bool);
    fn CGContextSetAllowsAntialiasing(c: CGContextRef, allowsAntialiasing: bool);
    fn CGContextSetShouldAntialias(c: CGContextRef, shouldAntialias: bool);
    fn CGContextSetAllowsFontSubpixelQuantization(c: CGContextRef,
                                                  allowsFontSubpixelQuantization: bool);
    fn CGContextSetShouldSubpixelQuantizeFonts(c: CGContextRef,
                                               shouldSubpixelQuantizeFonts: bool);
    fn CGContextSetAllowsFontSubpixelPositioning(c: CGContextRef,
                                                 allowsFontSubpixelPositioning: bool);
    fn CGContextSetShouldSubpixelPositionFonts(c: CGContextRef,
                                               shouldSubpixelPositionFonts: bool);
    fn CGContextSetTextDrawingMode(c: CGContextRef, mode: CGTextDrawingMode);
    fn CGContextSetRGBFillColor(context: CGContextRef,
                                red: CGFloat,
                                green: CGFloat,
                                blue: CGFloat,
                                alpha: CGFloat);
    fn CGContextFillRect(context: CGContextRef,
                         rect: CGRect);
    fn CGContextDrawImage(c: CGContextRef, rect: CGRect, image: CGImageRef);
}

<commit_msg>Add the posibility to specify buffer for CGContext<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use base::CGFloat;
use color_space::{CGColorSpace, CGColorSpaceRef};
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use libc::{c_void, size_t};
use std::mem;
use std::ptr;
use std::slice;
use geometry::CGRect;
use image::{CGImage, CGImageRef};

#[repr(C)]
pub enum CGTextDrawingMode {
    CGTextFill,
    CGTextStroke,
    CGTextFillStroke,
    CGTextInvisible,
    CGTextFillClip,
    CGTextStrokeClip,
    CGTextClip
}

#[repr(C)]
pub struct __CGContext;

pub type CGContextRef = *const __CGContext;

pub struct CGContext {
    obj: CGContextRef,
}

impl Drop for CGContext {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.as_CFTypeRef())
        }
    }
}

impl Clone for CGContext {
    fn clone(&self) -> CGContext {
        unsafe {
            TCFType::wrap_under_get_rule(self.as_concrete_TypeRef())
        }
    }
}

impl TCFType<CGContextRef> for CGContext {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CGContextRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CGContextRef) -> CGContext {
        let reference: CGContextRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CGContextRef) -> CGContext {
        CGContext {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CGContextGetTypeID()
        }
    }
}

impl CGContext {
    pub fn create_bitmap_context(data: Option<*mut c_void>,
                                 width: size_t,
                                 height: size_t,
                                 bits_per_component: size_t,
                                 bytes_per_row: size_t,
                                 space: &CGColorSpace,
                                 bitmap_info: u32)
                                 -> CGContext {
        unsafe {
            let result = CGBitmapContextCreate(data.unwrap_or(ptr::null_mut()),
                                               width,
                                               height,
                                               bits_per_component,
                                               bytes_per_row,
                                               space.as_concrete_TypeRef(),
                                               bitmap_info);
            TCFType::wrap_under_create_rule(result)
        }
    }

    pub fn data(&mut self) -> &mut [u8] {
        unsafe {
            slice::from_raw_parts_mut(
                    CGBitmapContextGetData(self.as_concrete_TypeRef()) as *mut u8,
                    (self.height() * self.bytes_per_row()) as usize)
        }
    }

    pub fn width(&self) -> size_t {
        unsafe {
            CGBitmapContextGetWidth(self.as_concrete_TypeRef())
        }
    }

    pub fn height(&self) -> size_t {
        unsafe {
            CGBitmapContextGetHeight(self.as_concrete_TypeRef())
        }
    }

    pub fn bytes_per_row(&self) -> size_t {
        unsafe {
            CGBitmapContextGetBytesPerRow(self.as_concrete_TypeRef())
        }
    }

    pub fn set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
        unsafe {
            CGContextSetRGBFillColor(self.as_concrete_TypeRef(), red, green, blue, alpha)
        }
    }

    pub fn set_allows_font_smoothing(&self, allows_font_smoothing: bool) {
        unsafe {
            CGContextSetAllowsFontSmoothing(self.as_concrete_TypeRef(), allows_font_smoothing)
        }
    }

    pub fn set_should_smooth_fonts(&self, should_smooth_fonts: bool) {
        unsafe {
            CGContextSetShouldSmoothFonts(self.as_concrete_TypeRef(), should_smooth_fonts)
        }
    }

    pub fn set_allows_antialiasing(&self, allows_antialiasing: bool) {
        unsafe {
            CGContextSetAllowsAntialiasing(self.as_concrete_TypeRef(), allows_antialiasing)
        }
    }

    pub fn set_should_antialias(&self, should_antialias: bool) {
        unsafe {
            CGContextSetShouldAntialias(self.as_concrete_TypeRef(), should_antialias)
        }
    }

    pub fn set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool) {
        unsafe {
            CGContextSetAllowsFontSubpixelQuantization(self.as_concrete_TypeRef(), allows_font_subpixel_quantization)
        }
    }

    pub fn set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool) {
        unsafe {
            CGContextSetShouldSubpixelQuantizeFonts(self.as_concrete_TypeRef(), should_subpixel_quantize_fonts)
        }
    }

    pub fn set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool) {
        unsafe {
            CGContextSetAllowsFontSubpixelPositioning(self.as_concrete_TypeRef(), allows_font_subpixel_positioning)
        }
    }

    pub fn set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool) {
        unsafe {
            CGContextSetShouldSubpixelPositionFonts(self.as_concrete_TypeRef(), should_subpixel_position_fonts)
        }
    }

    pub fn set_text_drawing_mode(&self, mode: CGTextDrawingMode) {
        unsafe {
            CGContextSetTextDrawingMode(self.as_concrete_TypeRef(), mode)
        }
    }

    pub fn fill_rect(&self, rect: CGRect) {
        unsafe {
            CGContextFillRect(self.as_concrete_TypeRef(), rect)
        }
    }

    pub fn draw_image(&self, rect: CGRect, image: &CGImage) {
        unsafe {
            CGContextDrawImage(self.as_concrete_TypeRef(), rect, image.as_concrete_TypeRef());
        }
    }

    pub fn create_image(&self) -> Option<CGImage> {
        let image = unsafe { CGBitmapContextCreateImage(self.as_concrete_TypeRef()) };
        if image != ptr::null() {
            Some(unsafe { CGImage::wrap_under_create_rule(image) })
        } else {
            None
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    fn CGBitmapContextCreate(data: *mut c_void,
                             width: size_t,
                             height: size_t,
                             bitsPerComponent: size_t,
                             bytesPerRow: size_t,
                             space: CGColorSpaceRef,
                             bitmapInfo: u32)
                             -> CGContextRef;
    fn CGBitmapContextGetData(context: CGContextRef) -> *mut c_void;
    fn CGBitmapContextGetWidth(context: CGContextRef) -> size_t;
    fn CGBitmapContextGetHeight(context: CGContextRef) -> size_t;
    fn CGBitmapContextGetBytesPerRow(context: CGContextRef) -> size_t;
    fn CGBitmapContextCreateImage(context: CGContextRef) -> CGImageRef;
    fn CGContextGetTypeID() -> CFTypeID;
    fn CGContextSetAllowsFontSmoothing(c: CGContextRef, allowsFontSmoothing: bool);
    fn CGContextSetShouldSmoothFonts(c: CGContextRef, shouldSmoothFonts: bool);
    fn CGContextSetAllowsAntialiasing(c: CGContextRef, allowsAntialiasing: bool);
    fn CGContextSetShouldAntialias(c: CGContextRef, shouldAntialias: bool);
    fn CGContextSetAllowsFontSubpixelQuantization(c: CGContextRef,
                                                  allowsFontSubpixelQuantization: bool);
    fn CGContextSetShouldSubpixelQuantizeFonts(c: CGContextRef,
                                               shouldSubpixelQuantizeFonts: bool);
    fn CGContextSetAllowsFontSubpixelPositioning(c: CGContextRef,
                                                 allowsFontSubpixelPositioning: bool);
    fn CGContextSetShouldSubpixelPositionFonts(c: CGContextRef,
                                               shouldSubpixelPositionFonts: bool);
    fn CGContextSetTextDrawingMode(c: CGContextRef, mode: CGTextDrawingMode);
    fn CGContextSetRGBFillColor(context: CGContextRef,
                                red: CGFloat,
                                green: CGFloat,
                                blue: CGFloat,
                                alpha: CGFloat);
    fn CGContextFillRect(context: CGContextRef,
                         rect: CGRect);
    fn CGContextDrawImage(c: CGContextRef, rect: CGRect, image: CGImageRef);
}

<|endoftext|>


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

use std::cell::RefCell;
use std::rc::Rc;

use super::{VertexBufferHandle,IndexBufferHandle,UniformBufferHandle,VertexArrayHandle,ProgramHandle,ShaderHandle};
use super::handle::{new_handle,HandleAccess};
use super::program::{self,Program,ProgramEditor,ProgramInfoAccessor};
use super::shader::{self,Shader,ShaderInfoAccessor,ShaderType};
use super::buffer;
use super::buffer::vertexbuffer::{VertexBuffer,VertexBufferEditor};
use super::buffer::uniformbuffer::{UniformBuffer,UniformBufferEditor};
use super::buffer::indexbuffer::IndexBufferEditor;
use super::vertexarray::{VertexArray,VertexAttribute,VertexAttributeType};
use super::renderer::Renderer;
use super::tracker::{SimpleBindingTracker,RenderBindingTracker,TrackerIdGenerator};
use super::info::{ContextInfo,build_info};

pub struct Context {
    info: ContextInfo,
    id_generator: TrackerIdGenerator,
    program_tracker: RenderBindingTracker<Program>,
    vbo_tracker: SimpleBindingTracker<VertexBuffer>,
    ubo_tracker: SimpleBindingTracker<UniformBuffer>,
    vao_tracker: RenderBindingTracker<VertexArray>,
    shared_state: Rc<RefCell<SharedContextState>>
}

impl Context {
    pub fn new() -> Context {
        Context {
            info: build_info(),
            id_generator: TrackerIdGenerator::new(),
            program_tracker: RenderBindingTracker::new(),
            vbo_tracker: SimpleBindingTracker::new(),
            ubo_tracker: SimpleBindingTracker::new(),
            vao_tracker: RenderBindingTracker::new(),
            shared_state: Rc::new(RefCell::new(SharedContextState::new()))
        }
    }

    // Construct new objects

    pub fn new_vertex_buffer(&mut self) -> VertexBufferHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(buffer::vertexbuffer::new_vertex_buffer(id, registration))
    }

    pub fn new_index_buffer(&mut self) -> IndexBufferHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(buffer::indexbuffer::new_index_buffer(id, registration))
    }

    pub fn new_uniform_buffer(&mut self) -> UniformBufferHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(buffer::uniformbuffer::new_uniform_buffer(id, registration))
    }

    pub fn new_vertex_array(&mut self,
                            attributes: &[VertexAttribute],
                            index_buffer: Option<IndexBufferHandle>) -> VertexArrayHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(VertexArray::new(self, id, attributes, index_buffer, registration))
    }

    pub fn new_vertex_array_simple(&mut self,
                                   attributes: &[(u8, VertexAttributeType, bool)],
                                   vertex_buffer: VertexBufferHandle,
                                   index_buffer: Option<IndexBufferHandle>) -> VertexArrayHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(VertexArray::new_single_vbo(self, id, attributes, vertex_buffer, index_buffer, registration))
    }

    pub fn new_shader(&mut self, shader_type: ShaderType, source: &str) -> ShaderHandle {
        let registration = self.registration_handle();
        new_handle(Shader::new(shader_type, source, registration))
    }

    pub fn new_program(&mut self, shaders: &[ShaderHandle]) -> ProgramHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(Program::new(id, shaders, registration))
    }

    // Modify object contents with the help of editor objects

    pub fn edit_vertex_buffer<'a>(&'a mut self, vbo: &'a VertexBufferHandle) -> VertexBufferEditor {
        buffer::vertexbuffer::new_vertex_buffer_editor(self, vbo.access())
    }

    pub fn edit_index_buffer<'a>(&'a mut self, vao: &'a VertexArrayHandle) -> Option<IndexBufferEditor> {
        let vao = vao.access();
        match vao.index_buffer() {
            Some(_) => Some(buffer::indexbuffer::new_index_buffer_editor(self, vao)),
            None => None
        }
    }

    pub fn edit_uniform_buffer<'a>(&'a mut self, ubo: &'a UniformBufferHandle) -> UniformBufferEditor {
        buffer::uniformbuffer::new_uniform_buffer_editor(self, ubo.access())
    }

    pub fn edit_program<'a>(&'a mut self, program: &'a ProgramHandle) -> ProgramEditor {
        program::new_program_editor(self, program.access())
    }

    pub fn program_info<'a>(&'a self, program: &'a ProgramHandle) -> ProgramInfoAccessor {
        program::new_program_info_accessor(program.access())
    }

    pub fn shader_info<'a>(&'a self, shader: &'a ShaderHandle) -> ShaderInfoAccessor {
        shader::new_shader_info_accessor(shader.access())
    }

    // Commands that do not (directly) consume resources

    pub fn renderer<'a>(&'a mut self) -> Renderer {
        Renderer::new(self)
    }

    // Expose context info to user too!
    pub fn get_info(&self) -> &ContextInfo {
        &self.info
    }

    // Internal stuff

    fn registration_handle(&self) -> RegistrationHandle {
        RegistrationHandle::new(self.shared_state.clone())
    }
}

#[unsafe_destructor]
impl Drop for Context {
    fn drop(&mut self) {
        self.shared_state.borrow_mut().context_alive = false;
    }
}

pub trait ContextEditingSupport {
    fn bind_vbo_for_editing(&mut self, vbo: &VertexBuffer);
    fn bind_ubo_for_editing(&mut self, vbo: &UniformBuffer);
    fn bind_vao_for_editing(&mut self, vao: &VertexArray);
    fn bind_program_for_editing(&mut self, program: &Program);
}

impl ContextEditingSupport for Context {
    fn bind_vbo_for_editing(&mut self, vbo: &VertexBuffer) {
        self.vbo_tracker.bind(vbo);
    }

    fn bind_ubo_for_editing(&mut self, ubo: &UniformBuffer) {
        self.ubo_tracker.bind(ubo);
    }

    fn bind_vao_for_editing(&mut self, vao: &VertexArray) {
        self.vao_tracker.bind_for_editing(vao);
    }

    fn bind_program_for_editing(&mut self, program: &Program) {
        self.program_tracker.bind_for_editing(program);
    }
}

pub trait ContextRenderingSupport {
    fn bind_vao_for_rendering(&mut self, vao: &VertexArrayHandle);
    fn bind_program_for_rendering(&mut self, program: &ProgramHandle);
    fn prepare_for_rendering(&mut self);
}

impl ContextRenderingSupport for Context {
    fn bind_vao_for_rendering(&mut self, vao: &VertexArrayHandle) {
        self.vao_tracker.bind_for_rendering(vao.rc());
    }

    fn bind_program_for_rendering(&mut self, program: &ProgramHandle) {
        self.program_tracker.bind_for_rendering(program.rc());
    }

    fn prepare_for_rendering(&mut self) {
        self.vao_tracker.restore_rendering_state();
        self.program_tracker.restore_rendering_state();
    }
}

pub struct SharedContextState {
    pub context_alive: bool
}

impl SharedContextState {
    pub fn new() -> SharedContextState {
        SharedContextState {
            context_alive: true
        }
    }
}

pub struct RegistrationHandle {
    context_shared: Rc<RefCell<SharedContextState>>
}

impl RegistrationHandle {
    pub fn new(context_shared: Rc<RefCell<SharedContextState>>) -> RegistrationHandle {
        RegistrationHandle { context_shared: context_shared }
    }

    pub fn context_alive(&self) -> bool {
        self.context_shared.borrow().context_alive
    }
}<commit_msg>Continue with documentation.<commit_after>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! See the struct `Context` for documentation on how the context is meant to be used.

use std::cell::RefCell;
use std::rc::Rc;

use super::{VertexBufferHandle,IndexBufferHandle,UniformBufferHandle,VertexArrayHandle,ProgramHandle,ShaderHandle};
use super::handle::{new_handle,HandleAccess};
use super::program::{self,Program,ProgramEditor,ProgramInfoAccessor};
use super::shader::{self,Shader,ShaderInfoAccessor,ShaderType};
use super::buffer;
use super::buffer::vertexbuffer::{VertexBuffer,VertexBufferEditor};
use super::buffer::uniformbuffer::{UniformBuffer,UniformBufferEditor};
use super::buffer::indexbuffer::IndexBufferEditor;
use super::vertexarray::{VertexArray,VertexAttribute,VertexAttributeType};
use super::renderer::Renderer;
use super::tracker::{SimpleBindingTracker,RenderBindingTracker,TrackerIdGenerator};
use super::info::{ContextInfo,build_info};

/// Context is a central concept in OpenGL, even though it's not a concrete item in the GL API.
/// This struct is meant to be a stand-in for the GL context, but also the starting point for all
/// the functionality this library offers.
///
/// # Contexts
///
/// Even though you're not prevented from instantiating more than one Contexts, you most likely
/// shouldn't. If you do, and use both contexts when only one actual OpenGL context is active,
/// things will not work as intended. This is an intentional trade-off. As mentioned, OpenGL API
/// does not expose the context in any explicit way, but this is in practice a property of the
/// windowing system. (For example, see wglMakeCurrent and glXMakeCurrent.) In addition, the
/// contexts may very well be managed by a wrapper library, abstracting away all the low-level and
/// platform specific peculiarities. This library would have to either work with only one of them,
/// many of them, or force you to make some kind of integration between this library and the other
/// library, giving the burden to you anyway. So, the main point still is: just don't create more
/// than one Context and you should be fine.
///
/// To create a Context object, call `Context::new()`.
///
/// # Resources
///
/// To create other objects, like vertex buffers or shaders, use the other new_-prefixed functions.
/// For example, to create a vertex buffer, call `ctx.new_vertex_buffer()`.
///
/// The resources are not returned themselves, but are always accessed through handles. This is
/// somewhat analogous with the way OpenGL API itself works. The main difference is that there is
/// no explicit bind method in this library, instead to edit an vertex buffer you call the
/// `edit_vertex_buffer` method of Context:
///
///    let vbo = ctx.new_vertex_buffer();
///    {
///        let editor = ctx.edit_vertex_buffer(&vbo);
///        editor.data(&vertex_data)
///    }
///
/// A shorter version with chaining:
///
///    let vbo = ctx.new_vertex_buffer();
///    ctx.edit_vertex_buffer(&vbo).data(&vertices);
///
/// ## Resource handles
///
/// The handles can be cloned and extend the lifetime of the actual resource in the same way
/// `std::rc::Rc` does. This is because some OpenGL resources may "embed" a resource in themselves.
/// And example of this is vertex arrays and index buffers. An index buffer may be attached to many
/// vertex arrays, and it needs to live as long as any of the vertex arrays live.
///
/// ## Editing is exclusive
///
/// You should notice that the edit_* functions borrow the context mutably, that is, there can
/// exist only one editor object at once. This is to ensure at compile time that the functions that
/// actually edit the one resource (for example `data` in the example above) specified. After all,
/// the underlying API doesn't allow having multiple vertex buffers bound at once, for example.
/// (The rules are more complicated for textures as there are several slots for textures.) The
/// limitation also works as a way to minimize the actual glBind* calls within the library.
///
/// ## Rendering mode
///
/// While binding resources is otherwise not explicitly exposed through the API, there is a
/// "rendering mode" that also borrows the context mutably, thus you can't issue rendering commands
/// and editing commands intertwined, at least not without creating (and destroying) editor and
/// renderer objects in large amounts. You can access the rendering mode by calling the
/// `renderer()` method. The `Renderer` struct has use_* methods that are analogous to the glBind*
/// functions, and also naturally the draw methods et cetera. See the Renderer documentation for
/// more about rendering.
pub struct Context {
    info: ContextInfo,
    id_generator: TrackerIdGenerator,
    program_tracker: RenderBindingTracker<Program>,
    vbo_tracker: SimpleBindingTracker<VertexBuffer>,
    ubo_tracker: SimpleBindingTracker<UniformBuffer>,
    vao_tracker: RenderBindingTracker<VertexArray>,
    shared_state: Rc<RefCell<SharedContextState>>
}

impl Context {
    /// Creates a new Context. Do not create more than one (per actual OpenGL context, anyway).
    ///
    /// See the documentation for the struct for more details.
    pub fn new() -> Context {
        Context {
            info: build_info(),
            id_generator: TrackerIdGenerator::new(),
            program_tracker: RenderBindingTracker::new(),
            vbo_tracker: SimpleBindingTracker::new(),
            ubo_tracker: SimpleBindingTracker::new(),
            vao_tracker: RenderBindingTracker::new(),
            shared_state: Rc::new(RefCell::new(SharedContextState::new()))
        }
    }

    // Construct new objects

    /// Create a new vertex buffer object.
    ///
    /// Returns a handle to the created vertex buffer.
    pub fn new_vertex_buffer(&mut self) -> VertexBufferHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(buffer::vertexbuffer::new_vertex_buffer(id, registration))
    }

    /// Create a new index buffer object.
    ///
    /// Returns a handle to the created index buffer.
    pub fn new_index_buffer(&mut self) -> IndexBufferHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(buffer::indexbuffer::new_index_buffer(id, registration))
    }

    /// Create a new uniform buffer object.
    ///
    /// Returns a handle to the created uniform buffer.
    pub fn new_uniform_buffer(&mut self) -> UniformBufferHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(buffer::uniformbuffer::new_uniform_buffer(id, registration))
    }

    /// Create a new vertex array object.
    ///
    /// See the `glVertexAttribPointer` documentation for how the attributes are specified.
    /// This function takes a slice of vertex attributes at once - the created vertex array
    /// is immutable, you can't change the attributes afterwards!
    ///
    /// If an index buffer should be associated with the vertex array, give a handle to it as the
    /// third argument.
    pub fn new_vertex_array(&mut self,
                            attributes: &[VertexAttribute],
                            index_buffer: Option<IndexBufferHandle>) -> VertexArrayHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(VertexArray::new(self, id, attributes, index_buffer, registration))
    }

    /// Create a new vertex array object that only uses contents of one vertex buffer.
    ///
    /// See the `glVertexAttribPointer` documentation for how the attributes slice works.
    /// Otherwise, see the `new_vertex_array` documentation. The only vertex array the vertex
    /// attributes refer to, are specified with the vertex_buffer argument.
    pub fn new_vertex_array_simple(&mut self,
                                   attributes: &[(u8, VertexAttributeType, bool)],
                                   vertex_buffer: VertexBufferHandle,
                                   index_buffer: Option<IndexBufferHandle>) -> VertexArrayHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(VertexArray::new_single_vbo(self, id, attributes, vertex_buffer, index_buffer, registration))
    }

    /// Create and compile a new shader object.
    pub fn new_shader(&mut self, shader_type: ShaderType, source: &str) -> ShaderHandle {
        let registration = self.registration_handle();
        new_handle(Shader::new(shader_type, source, registration))
    }

    /// Create and link a shader program from the specified shaders.
    pub fn new_program(&mut self, shaders: &[ShaderHandle]) -> ProgramHandle {
        let registration = self.registration_handle();
        let id = self.id_generator.new_id();
        new_handle(Program::new(id, shaders, registration))
    }

    // Modify object contents with the help of editor objects

    /// Edit a vertex buffer. Returns an editor object that can be used to modify the buffer
    /// contents.
    pub fn edit_vertex_buffer<'a>(&'a mut self, vbo: &'a VertexBufferHandle) -> VertexBufferEditor {
        buffer::vertexbuffer::new_vertex_buffer_editor(self, vbo.access())
    }

    /// Edit an index buffer. Returns an editor object that can be used to modify the buffer
    /// contents.
    ///
    /// Note that this function is given a *vertex array* instead of the index buffer directly.
    /// This is because the core OpenGL specification requires index buffers to be associated with
    /// an vertex array. The returned value is wrapped in an Option, because vertex arrays do not
    /// necessarily contain an index buffer. Still, it would be silly to call this function with a
    /// VAO that does not have an index buffer attached to it.
    pub fn edit_index_buffer<'a>(&'a mut self, vao: &'a VertexArrayHandle) -> Option<IndexBufferEditor> {
        let vao = vao.access();
        match vao.index_buffer() {
            Some(_) => Some(buffer::indexbuffer::new_index_buffer_editor(self, vao)),
            None => None
        }
    }

    pub fn edit_uniform_buffer<'a>(&'a mut self, ubo: &'a UniformBufferHandle) -> UniformBufferEditor {
        buffer::uniformbuffer::new_uniform_buffer_editor(self, ubo.access())
    }

    pub fn edit_program<'a>(&'a mut self, program: &'a ProgramHandle) -> ProgramEditor {
        program::new_program_editor(self, program.access())
    }

    pub fn program_info<'a>(&'a self, program: &'a ProgramHandle) -> ProgramInfoAccessor {
        program::new_program_info_accessor(program.access())
    }

    pub fn shader_info<'a>(&'a self, shader: &'a ShaderHandle) -> ShaderInfoAccessor {
        shader::new_shader_info_accessor(shader.access())
    }

    // Commands that do not (directly) consume resources

    pub fn renderer<'a>(&'a mut self) -> Renderer {
        Renderer::new(self)
    }

    // Expose context info to user too!
    pub fn get_info(&self) -> &ContextInfo {
        &self.info
    }

    // Internal stuff

    fn registration_handle(&self) -> RegistrationHandle {
        RegistrationHandle::new(self.shared_state.clone())
    }
}

#[unsafe_destructor]
impl Drop for Context {
    fn drop(&mut self) {
        self.shared_state.borrow_mut().context_alive = false;
    }
}

pub trait ContextEditingSupport {
    fn bind_vbo_for_editing(&mut self, vbo: &VertexBuffer);
    fn bind_ubo_for_editing(&mut self, vbo: &UniformBuffer);
    fn bind_vao_for_editing(&mut self, vao: &VertexArray);
    fn bind_program_for_editing(&mut self, program: &Program);
}

impl ContextEditingSupport for Context {
    fn bind_vbo_for_editing(&mut self, vbo: &VertexBuffer) {
        self.vbo_tracker.bind(vbo);
    }

    fn bind_ubo_for_editing(&mut self, ubo: &UniformBuffer) {
        self.ubo_tracker.bind(ubo);
    }

    fn bind_vao_for_editing(&mut self, vao: &VertexArray) {
        self.vao_tracker.bind_for_editing(vao);
    }

    fn bind_program_for_editing(&mut self, program: &Program) {
        self.program_tracker.bind_for_editing(program);
    }
}

pub trait ContextRenderingSupport {
    fn bind_vao_for_rendering(&mut self, vao: &VertexArrayHandle);
    fn bind_program_for_rendering(&mut self, program: &ProgramHandle);
    fn prepare_for_rendering(&mut self);
}

impl ContextRenderingSupport for Context {
    fn bind_vao_for_rendering(&mut self, vao: &VertexArrayHandle) {
        self.vao_tracker.bind_for_rendering(vao.rc());
    }

    fn bind_program_for_rendering(&mut self, program: &ProgramHandle) {
        self.program_tracker.bind_for_rendering(program.rc());
    }

    fn prepare_for_rendering(&mut self) {
        self.vao_tracker.restore_rendering_state();
        self.program_tracker.restore_rendering_state();
    }
}

pub struct SharedContextState {
    pub context_alive: bool
}

impl SharedContextState {
    pub fn new() -> SharedContextState {
        SharedContextState {
            context_alive: true
        }
    }
}

pub struct RegistrationHandle {
    context_shared: Rc<RefCell<SharedContextState>>
}

impl RegistrationHandle {
    pub fn new(context_shared: Rc<RefCell<SharedContextState>>) -> RegistrationHandle {
        RegistrationHandle { context_shared: context_shared }
    }

    pub fn context_alive(&self) -> bool {
        self.context_shared.borrow().context_alive
    }
}<|endoftext|>


<commit_before>use std::io::Read;
use std::io::Write;
use std::fs::File;

const EOD: u32 = 0x0067103A;
const EOF: u32 = 0x00845D52;

/// Position struct shared between Object, Polygon and Picture
pub struct Position {
    x: f64,
    y: f64
}

/// Type of object
enum ObjectType {
    Apple,
    Exit,
    Killer,
    Player
}

pub struct Object {
    position: Position,
    object_type: ObjectType,
    gravity: u32,
    animation: u32
}

pub struct Polygon {
    grass: bool,
    vertex_count: u32,
    vertices: Vec<Position>
}

pub struct Picture {
    name: [u8; 10],
    texture: [u8; 10],
    mask: [u8; 10],
    position: Position,
    distance: u32,
    clip: u32
}

/// Level struct that contains all level information
pub struct Level {
    /// Raw binary data of a loaded or finalized constructed level
    pub raw: Vec<u8>,
    /// Random number that links level file to replay files
    pub link: u32,
    /// Contains four integrity checks (See create_integrity())
    pub integrity: [f64; 4],
    /// Level name
    pub name: [u8; 51],
    /// LGR file name
    pub lgr: [u8; 16],
    /// Ground texture name
    pub ground: [u8; 10],
    /// Sky texture name
    pub sky: [u8; 10],
    /// Vector with all polygons (See Polygon)
    pub polygons: Vec<Polygon>,
    /// Vector with all objects (See Object)
    pub objects: Vec<Object>,
    /// Vector with all pictures (See Picture)
    pub pictures: Vec<Picture>
}

impl Level {
    /// Build a new Level
    pub fn new () -> Level {
        Level {
            raw: Vec::new(),
            link: 0,
            integrity: [0.0f64; 4],
            name: [0; 51],
            lgr: [0; 16],
            ground: [0; 10],
            sky: [0; 10],
            polygons: Vec::new(),
            objects: Vec::new(),
            pictures: Vec::new()
        }
    }

    /// Parses raw binary level data from self.raw and populates Level fields with information
    pub fn parse_level (&self) {

    }

    /// Loads level file data into self.raw field then calls self.parse_level()
    pub fn load_level (&mut self, filename: &str) {
        let mut file = File::open(filename).unwrap();
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer).unwrap();
        self.raw = buffer;
        self.parse_level();
    }

    /// Saves self.raw data to a file
    pub fn save_lev (&self, filename: &str) {
        let mut file = File::create(&filename).unwrap();
        file.write_all(b"Hello, world!").unwrap();
    }
}
<commit_msg>Add some preliminary doc strings all over<commit_after>use std::io::Read;
use std::io::Write;
use std::fs::File;

// Magic arbitrary number; signifies end-of-data. Followed by Top10 list(s).
const EOD: u32 = 0x0067103A;
// Magic arbitrary number; signifies end-of-file.
const EOF: u32 = 0x00845D52;

/// Position struct shared between Object, Polygon and Picture.
pub struct Position {
    /// X-position.
    x: f64,
    /// Y-position.
    y: f64
}

/// Type of object.
enum ObjectType {
    Apple,
    Exit,
    Killer,
    Player
}

/// Object struct. Every level requires one ObjectType::Player Object and at least one ObjectType::Exit Object.
pub struct Object {
    /// Position. See Position struct.
    position: Position,
    /// Type of Object, see ObjectType.
    object_type: ObjectType,
    /// Applies to ObjectType::Apple only.
    ///
    /// 0 = normal
    /// 1 = gravity up
    /// 2 = gravity down
    /// 3 = gravity left
    /// 4 = gravity right
    gravity: u32,
    /// Applies to ObjectType::Apple only. Valid values are 1 to 9.
    animation: u32
}

/// Polygon struct.
pub struct Polygon {
    /// Grass polygon.
    grass: bool,
    /// Vertices in Polygon.
    vertex_count: u32,
    /// Vector with all vertices, see Position struct.
    vertices: Vec<Position>
}

/// Picture struct.
pub struct Picture {
    /// Picture name.
    name: [u8; 10],
    /// Texture name.
    texture: [u8; 10],
    /// Mask name.
    mask: [u8; 10],
    /// Position. See Position struct.
    position: Position,
    /// Z-distance
    distance: u32,
    /// Clipping.
    ///
    /// 0 = unclipped
    /// 1 = ground
    /// 2 = sky
    clip: u32
}

/// Level struct that contains all level information
pub struct Level {
    /// Raw binary data of a loaded or finalized constructed level
    pub raw: Vec<u8>,
    /// Random number that links level file to replay files
    pub link: u32,
    /// Contains four integrity checks (See create_integrity())
    pub integrity: [f64; 4],
    /// Level name
    pub name: [u8; 51],
    /// LGR file name
    pub lgr: [u8; 16],
    /// Ground texture name
    pub ground: [u8; 10],
    /// Sky texture name
    pub sky: [u8; 10],
    /// Vector with all polygons (See Polygon)
    pub polygons: Vec<Polygon>,
    /// Vector with all objects (See Object)
    pub objects: Vec<Object>,
    /// Vector with all pictures (See Picture)
    pub pictures: Vec<Picture>
}

impl Level {
    /// Build a new Level.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::new();
    /// ```
    pub fn new () -> Level {
        Level {
            raw: Vec::new(),
            link: 0,
            integrity: [0.0f64; 4],
            name: [0; 51],
            lgr: [0; 16],
            ground: [0; 10],
            sky: [0; 10],
            polygons: Vec::new(),
            objects: Vec::new(),
            pictures: Vec::new()
        }
    }

    /// Parses raw binary level data from self.raw and populates Level fields with information
    pub fn parse_level (&self) {

    }

    /// Loads level file data into self.raw field then calls self.parse_level()
    pub fn load_level (&mut self, filename: &str) {
        let mut file = File::open(filename).unwrap();
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer).unwrap();
        self.raw = buffer;
        self.parse_level();
    }

    /// Saves self.raw data to a file
    pub fn save_lev (&self, filename: &str) {
        let mut file = File::create(&filename).unwrap();
        file.write_all(b"Hello, world!").unwrap();
    }
}
<|endoftext|>