<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Conversions of Rust values to and from `JSVal`.

use dom::bindings::js::{JS, JSRef, Root};
use dom::bindings::str::ByteString;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::bindings::utils::unwrap_jsmanaged;
use servo_util::str::DOMString;

use js::glue::{RUST_JSID_TO_STRING, RUST_JSID_IS_STRING};
use js::glue::RUST_JS_NumberValue;
use js::jsapi::{JSBool, JSContext, JSObject, JSString, jsid};
use js::jsapi::{JS_ValueToUint64, JS_ValueToInt64};
use js::jsapi::{JS_ValueToECMAUint32, JS_ValueToECMAInt32};
use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean};
use js::jsapi::{JS_ValueToString, JS_GetStringCharsAndLength};
use js::jsapi::{JS_NewUCStringCopyN, JS_NewStringCopyN};
use js::jsapi::{JS_WrapValue};
use js::jsval::JSVal;
use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value};
use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue};

use libc;
use std::default;
use std::slice;

use dom::bindings::codegen::PrototypeList;

// FIXME (https://github.com/rust-lang/rfcs/pull/4)
//       remove Option<Self> arguments.
pub trait IDLInterface {
    fn get_prototype_id(_: Option<Self>) -> PrototypeList::id::ID;
    fn get_prototype_depth(_: Option<Self>) -> uint;
}

/// A trait to convert Rust types to `JSVal`s.
pub trait ToJSValConvertible {
    /// Convert `self` to a `JSVal`. JSAPI failure causes a task failure.
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal;
}

/// A trait to convert `JSVal`s to Rust types.
pub trait FromJSValConvertible<T> {
    /// Convert `val` to type `Self`.
    /// Optional configuration of type `T` can be passed as the `option`
    /// argument.
    /// If it returns `Err(())`, a JSAPI exception is pending.
    fn from_jsval(cx: *mut JSContext, val: JSVal, option: T) -> Result<Self, ()>;
}

impl ToJSValConvertible for () {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        UndefinedValue()
    }
}

impl ToJSValConvertible for JSVal {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        let mut value = *self;
        if unsafe { JS_WrapValue(cx, &mut value) } == 0 {
            fail!("JS_WrapValue failed.");
        }
        value
    }
}

unsafe fn convert_from_jsval<T: default::Default>(
    cx: *mut JSContext, value: JSVal,
    convert_fn: unsafe extern "C" fn(*mut JSContext, JSVal, *mut T) -> JSBool) -> Result<T, ()> {
    let mut ret = default::Default::default();
    if convert_fn(cx, value, &mut ret) == 0 {
        Err(())
    } else {
        Ok(ret)
    }
}

impl ToJSValConvertible for bool {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        BooleanValue(*self)
    }
}

impl FromJSValConvertible<()> for bool {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<bool, ()> {
        let result = unsafe { convert_from_jsval(cx, val, JS_ValueToBoolean) };
        result.map(|b| b != 0)
    }
}

impl ToJSValConvertible for i8 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        Int32Value(*self as i32)
    }
}

impl FromJSValConvertible<()> for i8 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i8, ()> {
        let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) };
        result.map(|v| v as i8)
    }
}

impl ToJSValConvertible for u8 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        Int32Value(*self as i32)
    }
}

impl FromJSValConvertible<()> for u8 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u8, ()> {
        let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) };
        result.map(|v| v as u8)
    }
}

impl ToJSValConvertible for i16 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        Int32Value(*self as i32)
    }
}

impl FromJSValConvertible<()> for i16 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i16, ()> {
        let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) };
        result.map(|v| v as i16)
    }
}

impl ToJSValConvertible for u16 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        Int32Value(*self as i32)
    }
}

impl FromJSValConvertible<()> for u16 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u16, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToUint16) }
    }
}

impl ToJSValConvertible for i32 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        Int32Value(*self)
    }
}

impl FromJSValConvertible<()> for i32 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i32, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }
    }
}

impl ToJSValConvertible for u32 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        UInt32Value(*self)
    }
}

impl FromJSValConvertible<()> for u32 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u32, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToECMAUint32) }
    }
}

impl ToJSValConvertible for i64 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        unsafe {
            RUST_JS_NumberValue(*self as f64)
        }
    }
}

impl FromJSValConvertible<()> for i64 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i64, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToInt64) }
    }
}

impl ToJSValConvertible for u64 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        unsafe {
            RUST_JS_NumberValue(*self as f64)
        }
    }
}

impl FromJSValConvertible<()> for u64 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u64, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToUint64) }
    }
}

impl ToJSValConvertible for f32 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        unsafe {
            RUST_JS_NumberValue(*self as f64)
        }
    }
}

impl FromJSValConvertible<()> for f32 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<f32, ()> {
        let result = unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) };
        result.map(|f| f as f32)
    }
}

impl ToJSValConvertible for f64 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        unsafe {
            RUST_JS_NumberValue(*self)
        }
    }
}

impl FromJSValConvertible<()> for f64 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<f64, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) }
    }
}

impl ToJSValConvertible for DOMString {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        unsafe {
            let string_utf16: Vec<u16> = self.as_slice().utf16_units().collect();
            let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr(), string_utf16.len() as libc::size_t);
            if jsstr.is_null() {
                fail!("JS_NewUCStringCopyN failed");
            }
            StringValue(&*jsstr)
        }
    }
}

/// Behavior for stringification of `JSVal`s.
#[deriving(PartialEq)]
pub enum StringificationBehavior {
    /// Convert `null` to the string `"null"`.
    Default,
    /// Convert `null` to the empty string.
    Empty,
}

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

/// Convert the given `JSString` to a `DOMString`. Fails if the string does not
/// contain valid UTF-16.
pub fn jsstring_to_str(cx: *mut JSContext, s: *mut JSString) -> DOMString {
    unsafe {
        let mut length = 0;
        let chars = JS_GetStringCharsAndLength(cx, s, &mut length);
        slice::raw::buf_as_slice(chars, length as uint, |char_vec| {
            String::from_utf16(char_vec).unwrap()
        })
    }
}

/// Convert the given `jsid` to a `DOMString`. Fails if the `jsid` is not a
/// string, or if the string does not contain valid UTF-16.
pub fn jsid_to_str(cx: *mut JSContext, id: jsid) -> DOMString {
    unsafe {
        assert!(RUST_JSID_IS_STRING(id) != 0);
        jsstring_to_str(cx, RUST_JSID_TO_STRING(id))
    }
}

impl FromJSValConvertible<StringificationBehavior> for DOMString {
    fn from_jsval(cx: *mut JSContext, value: JSVal, nullBehavior: StringificationBehavior) -> Result<DOMString, ()> {
        if nullBehavior == Empty && value.is_null() {
            Ok("".to_string())
        } else {
            let jsstr = unsafe { JS_ValueToString(cx, value) };
            if jsstr.is_null() {
                debug!("JS_ValueToString failed");
                Err(())
            } else {
                Ok(jsstring_to_str(cx, jsstr))
            }
        }
    }
}

impl ToJSValConvertible for ByteString {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        unsafe {
            let slice = self.as_slice();
            let jsstr = JS_NewStringCopyN(cx, slice.as_ptr() as *const libc::c_char,
                                          slice.len() as libc::size_t);
            if jsstr.is_null() {
                fail!("JS_NewStringCopyN failed");
            }
            StringValue(&*jsstr)
        }
    }
}

impl FromJSValConvertible<()> for ByteString {
    fn from_jsval(cx: *mut JSContext, value: JSVal, _option: ()) -> Result<ByteString, ()> {
        unsafe {
            let string = JS_ValueToString(cx, value);
            if string.is_null() {
                debug!("JS_ValueToString failed");
                return Err(());
            }

            let mut length = 0;
            let chars = JS_GetStringCharsAndLength(cx, string, &mut length);
            slice::raw::buf_as_slice(chars, length as uint, |char_vec| {
                if char_vec.iter().any(|&c| c > 0xFF) {
                    // XXX Throw
                    Err(())
                } else {
                    Ok(ByteString::new(char_vec.iter().map(|&c| c as u8).collect()))
                }
            })
        }
    }
}

impl ToJSValConvertible for Reflector {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        let obj = self.get_jsobject();
        assert!(obj.is_not_null());
        let mut value = ObjectValue(unsafe { &*obj });
        if unsafe { JS_WrapValue(cx, &mut value) } == 0 {
            fail!("JS_WrapValue failed.");
        }
        value
    }
}

impl<T: Reflectable+IDLInterface> FromJSValConvertible<()> for JS<T> {
    fn from_jsval(_cx: *mut JSContext, value: JSVal, _option: ()) -> Result<JS<T>, ()> {
        if !value.is_object() {
            return Err(());
        }
        unwrap_jsmanaged(value.to_object(),
                         IDLInterface::get_prototype_id(None::<T>),
                         IDLInterface::get_prototype_depth(None::<T>))
    }
}

impl<'a, 'b, T: Reflectable> ToJSValConvertible for Root<'a, 'b, T> {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        self.reflector().to_jsval(cx)
    }
}

impl<'a, T: Reflectable> ToJSValConvertible for JSRef<'a, T> {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        self.reflector().to_jsval(cx)
    }
}

impl<'a, T: Reflectable> ToJSValConvertible for JS<T> {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        self.reflector().to_jsval(cx)
    }
}

impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        match self {
            &Some(ref value) => value.to_jsval(cx),
            &None => NullValue(),
        }
    }
}

impl<X: default::Default, T: FromJSValConvertible<X>> FromJSValConvertible<()> for Option<T> {
    fn from_jsval(cx: *mut JSContext, value: JSVal, _: ()) -> Result<Option<T>, ()> {
        if value.is_null_or_undefined() {
            Ok(None)
        } else {
            let option: X = default::Default::default();
            let result: Result<T, ()> = FromJSValConvertible::from_jsval(cx, value, option);
            result.map(Some)
        }
    }
}

impl ToJSValConvertible for *mut JSObject {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        let mut wrapped = ObjectOrNullValue(*self);
        unsafe {
            assert!(JS_WrapValue(cx, &mut wrapped) != 0);
        }
        wrapped
    }
}
<commit_msg>Document bindings/conversions.rs.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![deny(missing_doc)]

//! Conversions of Rust values to and from `JSVal`.

use dom::bindings::js::{JS, JSRef, Root};
use dom::bindings::str::ByteString;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::bindings::utils::unwrap_jsmanaged;
use servo_util::str::DOMString;

use js::glue::{RUST_JSID_TO_STRING, RUST_JSID_IS_STRING};
use js::glue::RUST_JS_NumberValue;
use js::jsapi::{JSBool, JSContext, JSObject, JSString, jsid};
use js::jsapi::{JS_ValueToUint64, JS_ValueToInt64};
use js::jsapi::{JS_ValueToECMAUint32, JS_ValueToECMAInt32};
use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean};
use js::jsapi::{JS_ValueToString, JS_GetStringCharsAndLength};
use js::jsapi::{JS_NewUCStringCopyN, JS_NewStringCopyN};
use js::jsapi::{JS_WrapValue};
use js::jsval::JSVal;
use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value};
use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue};

use libc;
use std::default;
use std::slice;

use dom::bindings::codegen::PrototypeList;

/// A trait to retrieve the constants necessary to check if a `JSObject`
/// implements a given interface.
// FIXME (https://github.com/rust-lang/rfcs/pull/4)
//       remove Option<Self> arguments.
pub trait IDLInterface {
    /// Returns the prototype ID.
    fn get_prototype_id(_: Option<Self>) -> PrototypeList::id::ID;
    /// Returns the prototype depth, i.e., the number of interfaces this
    /// interface inherits from.
    fn get_prototype_depth(_: Option<Self>) -> uint;
}

/// A trait to convert Rust types to `JSVal`s.
pub trait ToJSValConvertible {
    /// Convert `self` to a `JSVal`. JSAPI failure causes a task failure.
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal;
}

/// A trait to convert `JSVal`s to Rust types.
pub trait FromJSValConvertible<T> {
    /// Convert `val` to type `Self`.
    /// Optional configuration of type `T` can be passed as the `option`
    /// argument.
    /// If it returns `Err(())`, a JSAPI exception is pending.
    fn from_jsval(cx: *mut JSContext, val: JSVal, option: T) -> Result<Self, ()>;
}

impl ToJSValConvertible for () {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        UndefinedValue()
    }
}

impl ToJSValConvertible for JSVal {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        let mut value = *self;
        if unsafe { JS_WrapValue(cx, &mut value) } == 0 {
            fail!("JS_WrapValue failed.");
        }
        value
    }
}

unsafe fn convert_from_jsval<T: default::Default>(
    cx: *mut JSContext, value: JSVal,
    convert_fn: unsafe extern "C" fn(*mut JSContext, JSVal, *mut T) -> JSBool) -> Result<T, ()> {
    let mut ret = default::Default::default();
    if convert_fn(cx, value, &mut ret) == 0 {
        Err(())
    } else {
        Ok(ret)
    }
}

impl ToJSValConvertible for bool {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        BooleanValue(*self)
    }
}

impl FromJSValConvertible<()> for bool {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<bool, ()> {
        let result = unsafe { convert_from_jsval(cx, val, JS_ValueToBoolean) };
        result.map(|b| b != 0)
    }
}

impl ToJSValConvertible for i8 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        Int32Value(*self as i32)
    }
}

impl FromJSValConvertible<()> for i8 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i8, ()> {
        let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) };
        result.map(|v| v as i8)
    }
}

impl ToJSValConvertible for u8 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        Int32Value(*self as i32)
    }
}

impl FromJSValConvertible<()> for u8 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u8, ()> {
        let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) };
        result.map(|v| v as u8)
    }
}

impl ToJSValConvertible for i16 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        Int32Value(*self as i32)
    }
}

impl FromJSValConvertible<()> for i16 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i16, ()> {
        let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) };
        result.map(|v| v as i16)
    }
}

impl ToJSValConvertible for u16 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        Int32Value(*self as i32)
    }
}

impl FromJSValConvertible<()> for u16 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u16, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToUint16) }
    }
}

impl ToJSValConvertible for i32 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        Int32Value(*self)
    }
}

impl FromJSValConvertible<()> for i32 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i32, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }
    }
}

impl ToJSValConvertible for u32 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        UInt32Value(*self)
    }
}

impl FromJSValConvertible<()> for u32 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u32, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToECMAUint32) }
    }
}

impl ToJSValConvertible for i64 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        unsafe {
            RUST_JS_NumberValue(*self as f64)
        }
    }
}

impl FromJSValConvertible<()> for i64 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i64, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToInt64) }
    }
}

impl ToJSValConvertible for u64 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        unsafe {
            RUST_JS_NumberValue(*self as f64)
        }
    }
}

impl FromJSValConvertible<()> for u64 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u64, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToUint64) }
    }
}

impl ToJSValConvertible for f32 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        unsafe {
            RUST_JS_NumberValue(*self as f64)
        }
    }
}

impl FromJSValConvertible<()> for f32 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<f32, ()> {
        let result = unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) };
        result.map(|f| f as f32)
    }
}

impl ToJSValConvertible for f64 {
    fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
        unsafe {
            RUST_JS_NumberValue(*self)
        }
    }
}

impl FromJSValConvertible<()> for f64 {
    fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<f64, ()> {
        unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) }
    }
}

impl ToJSValConvertible for DOMString {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        unsafe {
            let string_utf16: Vec<u16> = self.as_slice().utf16_units().collect();
            let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr(), string_utf16.len() as libc::size_t);
            if jsstr.is_null() {
                fail!("JS_NewUCStringCopyN failed");
            }
            StringValue(&*jsstr)
        }
    }
}

/// Behavior for stringification of `JSVal`s.
#[deriving(PartialEq)]
pub enum StringificationBehavior {
    /// Convert `null` to the string `"null"`.
    Default,
    /// Convert `null` to the empty string.
    Empty,
}

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

/// Convert the given `JSString` to a `DOMString`. Fails if the string does not
/// contain valid UTF-16.
pub fn jsstring_to_str(cx: *mut JSContext, s: *mut JSString) -> DOMString {
    unsafe {
        let mut length = 0;
        let chars = JS_GetStringCharsAndLength(cx, s, &mut length);
        slice::raw::buf_as_slice(chars, length as uint, |char_vec| {
            String::from_utf16(char_vec).unwrap()
        })
    }
}

/// Convert the given `jsid` to a `DOMString`. Fails if the `jsid` is not a
/// string, or if the string does not contain valid UTF-16.
pub fn jsid_to_str(cx: *mut JSContext, id: jsid) -> DOMString {
    unsafe {
        assert!(RUST_JSID_IS_STRING(id) != 0);
        jsstring_to_str(cx, RUST_JSID_TO_STRING(id))
    }
}

impl FromJSValConvertible<StringificationBehavior> for DOMString {
    fn from_jsval(cx: *mut JSContext, value: JSVal, nullBehavior: StringificationBehavior) -> Result<DOMString, ()> {
        if nullBehavior == Empty && value.is_null() {
            Ok("".to_string())
        } else {
            let jsstr = unsafe { JS_ValueToString(cx, value) };
            if jsstr.is_null() {
                debug!("JS_ValueToString failed");
                Err(())
            } else {
                Ok(jsstring_to_str(cx, jsstr))
            }
        }
    }
}

impl ToJSValConvertible for ByteString {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        unsafe {
            let slice = self.as_slice();
            let jsstr = JS_NewStringCopyN(cx, slice.as_ptr() as *const libc::c_char,
                                          slice.len() as libc::size_t);
            if jsstr.is_null() {
                fail!("JS_NewStringCopyN failed");
            }
            StringValue(&*jsstr)
        }
    }
}

impl FromJSValConvertible<()> for ByteString {
    fn from_jsval(cx: *mut JSContext, value: JSVal, _option: ()) -> Result<ByteString, ()> {
        unsafe {
            let string = JS_ValueToString(cx, value);
            if string.is_null() {
                debug!("JS_ValueToString failed");
                return Err(());
            }

            let mut length = 0;
            let chars = JS_GetStringCharsAndLength(cx, string, &mut length);
            slice::raw::buf_as_slice(chars, length as uint, |char_vec| {
                if char_vec.iter().any(|&c| c > 0xFF) {
                    // XXX Throw
                    Err(())
                } else {
                    Ok(ByteString::new(char_vec.iter().map(|&c| c as u8).collect()))
                }
            })
        }
    }
}

impl ToJSValConvertible for Reflector {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        let obj = self.get_jsobject();
        assert!(obj.is_not_null());
        let mut value = ObjectValue(unsafe { &*obj });
        if unsafe { JS_WrapValue(cx, &mut value) } == 0 {
            fail!("JS_WrapValue failed.");
        }
        value
    }
}

impl<T: Reflectable+IDLInterface> FromJSValConvertible<()> for JS<T> {
    fn from_jsval(_cx: *mut JSContext, value: JSVal, _option: ()) -> Result<JS<T>, ()> {
        if !value.is_object() {
            return Err(());
        }
        unwrap_jsmanaged(value.to_object(),
                         IDLInterface::get_prototype_id(None::<T>),
                         IDLInterface::get_prototype_depth(None::<T>))
    }
}

impl<'a, 'b, T: Reflectable> ToJSValConvertible for Root<'a, 'b, T> {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        self.reflector().to_jsval(cx)
    }
}

impl<'a, T: Reflectable> ToJSValConvertible for JSRef<'a, T> {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        self.reflector().to_jsval(cx)
    }
}

impl<'a, T: Reflectable> ToJSValConvertible for JS<T> {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        self.reflector().to_jsval(cx)
    }
}

impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        match self {
            &Some(ref value) => value.to_jsval(cx),
            &None => NullValue(),
        }
    }
}

impl<X: default::Default, T: FromJSValConvertible<X>> FromJSValConvertible<()> for Option<T> {
    fn from_jsval(cx: *mut JSContext, value: JSVal, _: ()) -> Result<Option<T>, ()> {
        if value.is_null_or_undefined() {
            Ok(None)
        } else {
            let option: X = default::Default::default();
            let result: Result<T, ()> = FromJSValConvertible::from_jsval(cx, value, option);
            result.map(Some)
        }
    }
}

impl ToJSValConvertible for *mut JSObject {
    fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
        let mut wrapped = ObjectOrNullValue(*self);
        unsafe {
            assert!(JS_WrapValue(cx, &mut wrapped) != 0);
        }
        wrapped
    }
}
<|endoftext|>


<commit_before>// ignore-tidy-linelength
// only-macos
// no-system-llvm
// compile-flags: -O

#![crate_type = "rlib"]
#![feature(thread_local)]

// CHECK: @STATIC_VAR_1 = thread_local local_unnamed_addr global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4
#[no_mangle]
#[thread_local]
static mut STATIC_VAR_1: [u32; 8] = [0; 8];

// CHECK: @STATIC_VAR_2 = thread_local local_unnamed_addr global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4
#[no_mangle]
#[thread_local]
static mut STATIC_VAR_2: [u32; 8] = [4; 8];

#[no_mangle]
pub unsafe fn f(x: &mut [u32; 8]) {
    std::mem::swap(x, &mut STATIC_VAR_1)
}

#[no_mangle]
pub unsafe fn g(x: &mut [u32; 8]) {
    std::mem::swap(x, &mut STATIC_VAR_2)
}
<commit_msg>Disable 44056 test with debug on macos.<commit_after>// ignore-tidy-linelength
// only-macos
// no-system-llvm
// ignore-debug: the debug assertions get in the way
// compile-flags: -O

#![crate_type = "rlib"]
#![feature(thread_local)]

// CHECK: @STATIC_VAR_1 = thread_local local_unnamed_addr global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4
#[no_mangle]
#[thread_local]
static mut STATIC_VAR_1: [u32; 8] = [0; 8];

// CHECK: @STATIC_VAR_2 = thread_local local_unnamed_addr global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4
#[no_mangle]
#[thread_local]
static mut STATIC_VAR_2: [u32; 8] = [4; 8];

#[no_mangle]
pub unsafe fn f(x: &mut [u32; 8]) {
    std::mem::swap(x, &mut STATIC_VAR_1)
}

#[no_mangle]
pub unsafe fn g(x: &mut [u32; 8]) {
    std::mem::swap(x, &mut STATIC_VAR_2)
}
<|endoftext|>


<commit_before>use std::fmt;
use std::sync::{Arc, mpsc};
use std::sync::atomic::{AtomicBool, Ordering};
use mio;

use ::{Action, Message};
pub type Action_ = Action;
pub type Message_ = Message;

pub struct Transfer {
    token: mio::Token,
    notify: mio::Sender<Message>,
    is_notified: Arc<AtomicBool>,
    sender: mpsc::Sender<Action>,
}

pub fn new(token: mio::Token, notify: mio::Sender<Message_>, sender: mpsc::Sender<Action_>, is_notified: Arc<AtomicBool>) -> Transfer {
    Transfer {
        token: token,
        notify: notify,
        is_notified: is_notified,
        sender: sender,
    }
}

impl Transfer {

    pub fn write(&mut self, data: &[u8]) {
        self.send(Action::Write(Some(data.to_vec())));
    }

    pub fn eof(&mut self) {
        self.send(Action::Write(None));
    }

    pub fn resume(&mut self) {
        self.notify.send(
            Message::Action(self.token, Action::Register(mio::EventSet::readable()))
        ).unwrap();
    }

    pub fn close(&mut self) {
        //TODO: consume self?
        self.notify.send(
            Message::Action(self.token, Action::Close)
        ).unwrap();
    }

    fn send(&self, action: Action) {
        if self.is_notified.load(Ordering::Acquire) {
            self.sender.send(action);
        } else {
            self.notify.send(Message::Action(self.token, action)).unwrap();
            self.is_notified.store(true, Ordering::Release);
        }
    }
    // fn abort()
    // fn pause()
}

impl fmt::Debug for Transfer {
    fn fmt(&self, f: &mut fmt::Foramtter) -> fmt::Result {
        f.debug_struct("Transfer")
            .field("token", &self.token)
            .finish()
    }
}

impl Drop for Transfer {
    fn drop(&mut self) {
        self.close();
    }
}
<commit_msg>formatter typo<commit_after>use std::fmt;
use std::sync::{Arc, mpsc};
use std::sync::atomic::{AtomicBool, Ordering};
use mio;

use ::{Action, Message};
pub type Action_ = Action;
pub type Message_ = Message;

pub struct Transfer {
    token: mio::Token,
    notify: mio::Sender<Message>,
    is_notified: Arc<AtomicBool>,
    sender: mpsc::Sender<Action>,
}

pub fn new(token: mio::Token, notify: mio::Sender<Message_>, sender: mpsc::Sender<Action_>, is_notified: Arc<AtomicBool>) -> Transfer {
    Transfer {
        token: token,
        notify: notify,
        is_notified: is_notified,
        sender: sender,
    }
}

impl Transfer {

    pub fn write(&mut self, data: &[u8]) {
        self.send(Action::Write(Some(data.to_vec())));
    }

    pub fn eof(&mut self) {
        self.send(Action::Write(None));
    }

    pub fn resume(&mut self) {
        self.notify.send(
            Message::Action(self.token, Action::Register(mio::EventSet::readable()))
        ).unwrap();
    }

    pub fn close(&mut self) {
        //TODO: consume self?
        self.notify.send(
            Message::Action(self.token, Action::Close)
        ).unwrap();
    }

    fn send(&self, action: Action) {
        if self.is_notified.load(Ordering::Acquire) {
            self.sender.send(action);
        } else {
            self.notify.send(Message::Action(self.token, action)).unwrap();
            self.is_notified.store(true, Ordering::Release);
        }
    }
    // fn abort()
    // fn pause()
}

impl fmt::Debug for Transfer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Transfer")
            .field("token", &self.token)
            .finish()
    }
}

impl Drop for Transfer {
    fn drop(&mut self) {
        self.close();
    }
}
<|endoftext|>


<commit_before>extern crate libc;
use super::{Width, Height};
use std::os::raw::*;

#[derive(Debug)]
struct WinSize {
    ws_row: c_ushort,
    ws_col: c_ushort,
    ws_xpixel: c_ushort,
    ws_ypixel: c_ushort,
}

/// Returns the size of the terminal, if available.
///
/// If STDOUT is not a tty, returns `None`
pub fn terminal_size() -> Option<(Width, Height)> {
    use self::libc::{ioctl, isatty, STDOUT_FILENO, TIOCGWINSZ};
    let is_tty: bool = unsafe { isatty(STDOUT_FILENO) == 1 };

    if !is_tty {
        return None;
    }

    let (rows, cols) = unsafe {
        let mut winsize = WinSize {
            ws_row: 0,
            ws_col: 0,
            ws_xpixel: 0,
            ws_ypixel: 0,
        };
        ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut winsize);
        let rows = if winsize.ws_row > 0 {
            winsize.ws_row
        } else {
            0
        };
        let cols = if winsize.ws_col > 0 {
            winsize.ws_col
        } else {
            0
        };
        (rows as u16, cols as u16)
    };

    if rows > 0 && cols > 0 {
        Some((Width(cols), Height(rows)))
    } else {
        None
    }
}

#[test]
/// Compare with the output of `stty size`
fn compare_with_stty() {
    use std::process::Command;
    use std::process::Stdio;
    let mut args = vec!["-F", "/dev/stderr", "size"];
    if cfg!(target_os = "macos") {
        args[0] = "-f"
    }
    let output = Command::new("stty")
                     .args(&args)
                     .stderr(Stdio::inherit())
                     .output()
                     .unwrap();
    let stdout = String::from_utf8(output.stdout).unwrap();
    assert!(output.status.success());

    // stdout is "rows cols"
    let mut data = stdout.split_whitespace();
    let rows = u16::from_str_radix(data.next().unwrap(), 10).unwrap();
    let cols = u16::from_str_radix(data.next().unwrap(), 10).unwrap();
    println!("{}", stdout);
    println!("{} {}", rows, cols);

    if let Some((Width(w), Height(h))) = terminal_size() {
        assert_eq!(rows, h);
        assert_eq!(cols, w);
    }
}
<commit_msg>fix(tty/unix): make the program build<commit_after>extern crate libc;
use super::{Width, Height};
use std::os::raw::*;

#[cfg(not(target_os = "macos"))]
const TIOCGWINSZ: c_int = 0x00005413;
#[cfg(target_os = "macos")]
const TIOCGWINSZ: c_ulong = 1074295912;

#[derive(Debug)]
struct WinSize {
    ws_row: c_ushort,
    ws_col: c_ushort,
    ws_xpixel: c_ushort,
    ws_ypixel: c_ushort,
}

/// Returns the size of the terminal, if available.
///
/// If STDOUT is not a tty, returns `None`
pub fn terminal_size() -> Option<(Width, Height)> {
    use self::libc::{ioctl, isatty, STDOUT_FILENO};
    let is_tty: bool = unsafe { isatty(STDOUT_FILENO) == 1 };

    if !is_tty {
        return None;
    }

    let (rows, cols) = unsafe {
        let mut winsize = WinSize {
            ws_row: 0,
            ws_col: 0,
            ws_xpixel: 0,
            ws_ypixel: 0,
        };
        ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut winsize);
        let rows = if winsize.ws_row > 0 {
            winsize.ws_row
        } else {
            0
        };
        let cols = if winsize.ws_col > 0 {
            winsize.ws_col
        } else {
            0
        };
        (rows as u16, cols as u16)
    };

    if rows > 0 && cols > 0 {
        Some((Width(cols), Height(rows)))
    } else {
        None
    }
}

#[test]
/// Compare with the output of `stty size`
fn compare_with_stty() {
    use std::process::Command;
    use std::process::Stdio;
    let mut args = vec!["-F", "/dev/stderr", "size"];
    if cfg!(target_os = "macos") {
        args[0] = "-f"
    }
    let output = Command::new("stty")
                     .args(&args)
                     .stderr(Stdio::inherit())
                     .output()
                     .unwrap();
    let stdout = String::from_utf8(output.stdout).unwrap();
    assert!(output.status.success());

    // stdout is "rows cols"
    let mut data = stdout.split_whitespace();
    let rows = u16::from_str_radix(data.next().unwrap(), 10).unwrap();
    let cols = u16::from_str_radix(data.next().unwrap(), 10).unwrap();
    println!("{}", stdout);
    println!("{} {}", rows, cols);

    if let Some((Width(w), Height(h))) = terminal_size() {
        assert_eq!(rows, h);
        assert_eq!(cols, w);
    }
}
<|endoftext|>


<commit_before>use crate::FileTime;
use libc::{time_t, timespec};
use std::fs;
use std::os::unix::prelude::*;

cfg_if::cfg_if! {
    if #[cfg(target_os = "linux")] {
        mod utimes;
        mod linux;
        pub use self::linux::*;
    } else if #[cfg(target_os = "android")] {
        mod utimes;
        mod android;
        pub use self::android::*;
    } else if #[cfg(target_os = "macos")] {
        mod utimes;
        mod macos;
        pub use self::macos::*;
    } else if #[cfg(any(target_os = "solaris",
                        target_os = "illumos",
                        target_os = "emscripten",
                        target_os = "freebsd",
                        target_os = "netbsd",
                        target_os = "openbsd",
                        target_os = "haiku"))] {
        mod utimensat;
        pub use self::utimensat::*;
    } else {
        mod utimes;
        pub use self::utimes::*;
    }
}

#[allow(dead_code)]
fn to_timespec(ft: &Option<FileTime>) -> timespec {
    cfg_if::cfg_if! {
        if #[cfg(target_os = "macos")] {
            // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/sys/stat.h#L541
            const UTIME_OMIT: i64 = -2;
        } else {
            const UTIME_OMIT: i64 = 1_073_741_822;
        }
    }

    if let &Some(ft) = ft {
        timespec {
            tv_sec: ft.seconds() as time_t,
            tv_nsec: ft.nanoseconds() as _,
        }
    } else {
        timespec {
            tv_sec: 0,
            tv_nsec: UTIME_OMIT as _,
        }
    }
}

pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.mtime(),
        nanos: meta.mtime_nsec() as u32,
    }
}

pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.atime(),
        nanos: meta.atime_nsec() as u32,
    }
}

pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
    macro_rules! birthtim {
        ($(($e:expr, $i:ident)),*) => {
            #[cfg(any($(target_os = $e),*))]
            fn imp(meta: &fs::Metadata) -> Option<FileTime> {
                $(
                    #[cfg(target_os = $e)]
                    use std::os::$i::fs::MetadataExt;
                )*
                Some(FileTime {
                    seconds: meta.st_birthtime(),
                    nanos: meta.st_birthtime_nsec() as u32,
                })
            }

            #[cfg(all($(not(target_os = $e)),*))]
            fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
                None
            }
        }
    }

    birthtim! {
        ("bitrig", bitrig),
        ("freebsd", freebsd),
        ("ios", ios),
        ("macos", macos),
        ("openbsd", openbsd)
    }

    imp(meta)
}
<commit_msg>Setting UTIME_OMIT correctly for OpenBSD (#60)<commit_after>use crate::FileTime;
use libc::{time_t, timespec};
use std::fs;
use std::os::unix::prelude::*;

cfg_if::cfg_if! {
    if #[cfg(target_os = "linux")] {
        mod utimes;
        mod linux;
        pub use self::linux::*;
    } else if #[cfg(target_os = "android")] {
        mod utimes;
        mod android;
        pub use self::android::*;
    } else if #[cfg(target_os = "macos")] {
        mod utimes;
        mod macos;
        pub use self::macos::*;
    } else if #[cfg(any(target_os = "solaris",
                        target_os = "illumos",
                        target_os = "emscripten",
                        target_os = "freebsd",
                        target_os = "netbsd",
                        target_os = "openbsd",
                        target_os = "haiku"))] {
        mod utimensat;
        pub use self::utimensat::*;
    } else {
        mod utimes;
        pub use self::utimes::*;
    }
}

#[allow(dead_code)]
fn to_timespec(ft: &Option<FileTime>) -> timespec {
    cfg_if::cfg_if! {
        if #[cfg(target_os = "macos")] {
            // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/sys/stat.h#L541
            const UTIME_OMIT: i64 = -2;
        } else if #[cfg(target_os = "openbsd")] {
            // https://github.com/openbsd/src/blob/master/sys/sys/stat.h#L189
            const UTIME_OMIT: i64 = -1;
        } else {
            const UTIME_OMIT: i64 = 1_073_741_822;
        }
    }

    if let &Some(ft) = ft {
        timespec {
            tv_sec: ft.seconds() as time_t,
            tv_nsec: ft.nanoseconds() as _,
        }
    } else {
        timespec {
            tv_sec: 0,
            tv_nsec: UTIME_OMIT as _,
        }
    }
}

pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.mtime(),
        nanos: meta.mtime_nsec() as u32,
    }
}

pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.atime(),
        nanos: meta.atime_nsec() as u32,
    }
}

pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
    macro_rules! birthtim {
        ($(($e:expr, $i:ident)),*) => {
            #[cfg(any($(target_os = $e),*))]
            fn imp(meta: &fs::Metadata) -> Option<FileTime> {
                $(
                    #[cfg(target_os = $e)]
                    use std::os::$i::fs::MetadataExt;
                )*
                Some(FileTime {
                    seconds: meta.st_birthtime(),
                    nanos: meta.st_birthtime_nsec() as u32,
                })
            }

            #[cfg(all($(not(target_os = $e)),*))]
            fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
                None
            }
        }
    }

    birthtim! {
        ("bitrig", bitrig),
        ("freebsd", freebsd),
        ("ios", ios),
        ("macos", macos),
        ("openbsd", openbsd)
    }

    imp(meta)
}
<|endoftext|>


<commit_before>use std::path::{Path, Component};
use std::error::Error;
use std::io::{self, Read};
use std::fs::{self, metadata, File};

/// Takes a path to a file and try to read the file into a String

pub fn file_to_string(path: &Path) -> Result<String, Box<Error>> {
    let mut file = match File::open(path) {
        Ok(f) => f,
        Err(e) => {
            debug!("[*]: Failed to open {:?}", path);
            return Err(Box::new(e));
        },
    };

    let mut content = String::new();

    if let Err(e) = file.read_to_string(&mut content) {
        debug!("[*]: Failed to read {:?}", path);
        return Err(Box::new(e));
    }

    Ok(content)
}

/// Takes a path and returns a path containing just enough `../` to point to the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the directory from where the
/// path starts.
///
/// ```ignore
/// let mut path = Path::new("some/relative/path");
///
/// println!("{}", path_to_root(&path));
/// ```
///
/// **Outputs**
///
/// ```text
/// "../../"
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where it doesn't return the correct
/// path. Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues) or a
/// [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it.

pub fn path_to_root(path: &Path) -> String {
    debug!("[fn]: path_to_root");
    // Remove filename and add "../" for every directory

    path.to_path_buf()
        .parent()
        .expect("")
        .components()
        .fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("[*]: Other path component... {:?}", c);
                },
            }
            s
        })
}

/// This function creates a file and returns it. But before creating the file it checks every
/// directory in the path to see if it exists, and if it does not it will be created.

pub fn create_file(path: &Path) -> Result<File, Box<Error>> {
    debug!("[fn]: create_file");

    // Construct path
    if let Some(p) = path.parent() {
        debug!("Parent directory is: {:?}", p);

        try!(fs::create_dir_all(p));
    }

    debug!("[*]: Create file: {:?}", path);
    let f = match File::create(path) {
        Ok(f) => f,
        Err(e) => {
            debug!("File::create:    {}", e);
            return Err(Box::new(io::Error::new(io::ErrorKind::Other, format!("{}", e))));
        },
    };

    Ok(f)
}

/// Removes all the content of a directory but not the directory itself

pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> {
    for item in try!(fs::read_dir(dir)) {
        if let Ok(item) = item {
            let item = item.path();
            if item.is_dir() {
                try!(fs::remove_dir_all(item));
            } else {
                try!(fs::remove_file(item));
            }
        }
    }
    Ok(())
}

///
///
/// Copies all files of a directory to another one except the files with the extensions given in the
/// `ext_blacklist` array

pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) -> Result<(), Box<Error>> {
    debug!("[fn] copy_files_except_ext");
    // Check that from and to are different
    if from == to {
        return Ok(());
    }
    debug!("[*] Loop");
    for entry in try!(fs::read_dir(from)) {
        let entry = try!(entry);
        debug!("[*] {:?}", entry.path());
        let metadata = try!(entry.metadata());

        // If the entry is a dir and the recursive option is enabled, call itself
        if metadata.is_dir() && recursive {
            if entry.path() == to.to_path_buf() {
                continue;
            }
            debug!("[*] is dir");

            // check if output dir already exists
            if !to.join(entry.file_name()).exists() {
                try!(fs::create_dir(&to.join(entry.file_name())));
            }

            try!(copy_files_except_ext(&from.join(entry.file_name()),
                                       &to.join(entry.file_name()),
                                       true,
                                       ext_blacklist));
        } else if metadata.is_file() {

            // Check if it is in the blacklist
            if let Some(ext) = entry.path().extension() {
                if ext_blacklist.contains(&ext.to_str().unwrap()) {
                    continue;
                }
            }
            debug!("[*] creating path for file: {:?}",
                   &to.join(entry.path().file_name().expect("a file should have a file name...")));

            info!("[*] Copying file: {:?}\n    to {:?}",
                  entry.path(),
                  &to.join(entry.path().file_name().expect("a file should have a file name...")));
            try!(fs::copy(entry.path(),
                          &to.join(entry.path().file_name().expect("a file should have a file name..."))));
        }
    }
    Ok(())
}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------

// tests

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::copy_files_except_ext;
    use std::fs;

    #[test]
    fn copy_files_except_ext_test() {
        let tmp = match tempdir::TempDir::new("") {
            Ok(t) => t,
            Err(_) => panic!("Could not create a temp dir"),
        };

        // Create a couple of files
        if let Err(_) = fs::File::create(&tmp.path().join("file.txt")) {
            panic!("Could not create file.txt")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("file.md")) {
            panic!("Could not create file.md")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("file.png")) {
            panic!("Could not create file.png")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir")) {
            panic!("Could not create sub_dir")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("sub_dir/file.png")) {
            panic!("Could not create sub_dir/file.png")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir_exists")) {
            panic!("Could not create sub_dir_exists")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) {
            panic!("Could not create sub_dir_exists/file.txt")
        }

        // Create output dir
        if let Err(_) = fs::create_dir(&tmp.path().join("output")) {
            panic!("Could not create output")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) {
            panic!("Could not create output/sub_dir_exists")
        }

        match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) {
            Err(e) => panic!("Error while executing the function:\n{:?}", e),
            Ok(_) => {},
        }

        // Check if the correct files where created
        if !(&tmp.path().join("output/file.txt")).exists() {
            panic!("output/file.txt should exist")
        }
        if (&tmp.path().join("output/file.md")).exists() {
            panic!("output/file.md should not exist")
        }
        if !(&tmp.path().join("output/file.png")).exists() {
            panic!("output/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir/file.png")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }

    }
}
<commit_msg>Remove unused metadata import<commit_after>use std::path::{Path, Component};
use std::error::Error;
use std::io::{self, Read};
use std::fs::{self, File};

/// Takes a path to a file and try to read the file into a String

pub fn file_to_string(path: &Path) -> Result<String, Box<Error>> {
    let mut file = match File::open(path) {
        Ok(f) => f,
        Err(e) => {
            debug!("[*]: Failed to open {:?}", path);
            return Err(Box::new(e));
        },
    };

    let mut content = String::new();

    if let Err(e) = file.read_to_string(&mut content) {
        debug!("[*]: Failed to read {:?}", path);
        return Err(Box::new(e));
    }

    Ok(content)
}

/// Takes a path and returns a path containing just enough `../` to point to the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the directory from where the
/// path starts.
///
/// ```ignore
/// let mut path = Path::new("some/relative/path");
///
/// println!("{}", path_to_root(&path));
/// ```
///
/// **Outputs**
///
/// ```text
/// "../../"
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where it doesn't return the correct
/// path. Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues) or a
/// [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it.

pub fn path_to_root(path: &Path) -> String {
    debug!("[fn]: path_to_root");
    // Remove filename and add "../" for every directory

    path.to_path_buf()
        .parent()
        .expect("")
        .components()
        .fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("[*]: Other path component... {:?}", c);
                },
            }
            s
        })
}

/// This function creates a file and returns it. But before creating the file it checks every
/// directory in the path to see if it exists, and if it does not it will be created.

pub fn create_file(path: &Path) -> Result<File, Box<Error>> {
    debug!("[fn]: create_file");

    // Construct path
    if let Some(p) = path.parent() {
        debug!("Parent directory is: {:?}", p);

        try!(fs::create_dir_all(p));
    }

    debug!("[*]: Create file: {:?}", path);
    let f = match File::create(path) {
        Ok(f) => f,
        Err(e) => {
            debug!("File::create:    {}", e);
            return Err(Box::new(io::Error::new(io::ErrorKind::Other, format!("{}", e))));
        },
    };

    Ok(f)
}

/// Removes all the content of a directory but not the directory itself

pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> {
    for item in try!(fs::read_dir(dir)) {
        if let Ok(item) = item {
            let item = item.path();
            if item.is_dir() {
                try!(fs::remove_dir_all(item));
            } else {
                try!(fs::remove_file(item));
            }
        }
    }
    Ok(())
}

///
///
/// Copies all files of a directory to another one except the files with the extensions given in the
/// `ext_blacklist` array

pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) -> Result<(), Box<Error>> {
    debug!("[fn] copy_files_except_ext");
    // Check that from and to are different
    if from == to {
        return Ok(());
    }
    debug!("[*] Loop");
    for entry in try!(fs::read_dir(from)) {
        let entry = try!(entry);
        debug!("[*] {:?}", entry.path());
        let metadata = try!(entry.metadata());

        // If the entry is a dir and the recursive option is enabled, call itself
        if metadata.is_dir() && recursive {
            if entry.path() == to.to_path_buf() {
                continue;
            }
            debug!("[*] is dir");

            // check if output dir already exists
            if !to.join(entry.file_name()).exists() {
                try!(fs::create_dir(&to.join(entry.file_name())));
            }

            try!(copy_files_except_ext(&from.join(entry.file_name()),
                                       &to.join(entry.file_name()),
                                       true,
                                       ext_blacklist));
        } else if metadata.is_file() {

            // Check if it is in the blacklist
            if let Some(ext) = entry.path().extension() {
                if ext_blacklist.contains(&ext.to_str().unwrap()) {
                    continue;
                }
            }
            debug!("[*] creating path for file: {:?}",
                   &to.join(entry.path().file_name().expect("a file should have a file name...")));

            info!("[*] Copying file: {:?}\n    to {:?}",
                  entry.path(),
                  &to.join(entry.path().file_name().expect("a file should have a file name...")));
            try!(fs::copy(entry.path(),
                          &to.join(entry.path().file_name().expect("a file should have a file name..."))));
        }
    }
    Ok(())
}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------

// tests

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::copy_files_except_ext;
    use std::fs;

    #[test]
    fn copy_files_except_ext_test() {
        let tmp = match tempdir::TempDir::new("") {
            Ok(t) => t,
            Err(_) => panic!("Could not create a temp dir"),
        };

        // Create a couple of files
        if let Err(_) = fs::File::create(&tmp.path().join("file.txt")) {
            panic!("Could not create file.txt")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("file.md")) {
            panic!("Could not create file.md")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("file.png")) {
            panic!("Could not create file.png")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir")) {
            panic!("Could not create sub_dir")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("sub_dir/file.png")) {
            panic!("Could not create sub_dir/file.png")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir_exists")) {
            panic!("Could not create sub_dir_exists")
        }
        if let Err(_) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) {
            panic!("Could not create sub_dir_exists/file.txt")
        }

        // Create output dir
        if let Err(_) = fs::create_dir(&tmp.path().join("output")) {
            panic!("Could not create output")
        }
        if let Err(_) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) {
            panic!("Could not create output/sub_dir_exists")
        }

        match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) {
            Err(e) => panic!("Error while executing the function:\n{:?}", e),
            Ok(_) => {},
        }

        // Check if the correct files where created
        if !(&tmp.path().join("output/file.txt")).exists() {
            panic!("output/file.txt should exist")
        }
        if (&tmp.path().join("output/file.md")).exists() {
            panic!("output/file.md should not exist")
        }
        if !(&tmp.path().join("output/file.png")).exists() {
            panic!("output/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir/file.png")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }

    }
}
<|endoftext|>


<commit_before>/// Brainfuck is represented by an array with 30,000 cells initialized to zero
/// and a data pointer pointing at the current cell.
///
/// There are eight commands:
/// + : Increments the value at the current cell by one.
/// - : Decrements the value at the current cell by one.
/// > : Moves the data pointer to the next cell (cell on the right).
/// < : Moves the data pointer to the previous cell (cell on the left).
/// . : Prints the ASCII value at the current cell (i.e. 65 = 'A').
/// , : Reads a single input character into the current cell.
/// [ : If the value at the current cell is zero, skips to the
///     corresponding ] . Otherwise, move to the next instruction.
/// ] : If the value at the current cell is zero, move to the next instruction.
///     Otherwise, move backwards in the instructions to the corresponding [ .
///
/// Note: the previous descriptions are according to the def'n of the spec.
///       Implementation specific descriptions are with the corresponding fns.
pub struct VMState {
    stack : [u8; 30000],
    p : usize,
}
impl VMState {
    pub fn new () -> VMState {
        VMState {
            stack : [0; 30000],
            p : 0
        }
    }
    /// '+' : Increments the value at the current cell by one.
    fn inc_val (&mut self) {
        self.stack[self.p] = self.stack[self.p].wrapping_add(1);
    }
    /// '-' : Decrements the value at the current cell by one.
    fn dec_val (&mut self) {
        self.stack[self.p] = self.stack[self.p].wrapping_sub(1);
    }
    /// '>' : Moves the data pointer to the next cell (cell on the right).
    fn inc_ptr (&mut self) {
        self.p += 1;
    }
    /// '<' : Moves the data pointer to the previous cell (cell on the left).
    fn dec_ptr (&mut self) {
        self.p -= 1;
    }
    /// '.' : Returns the ASCII value at the current cell (i.e. 65 = 'A').
    fn std_out (&mut self) -> u8 {
        return (self.stack[self.p]);
    }
    /// ',' : Reads a single input character into the current cell.
    fn std_in (&mut self, input:u8) {
        self.stack[self.p] = input;
    }

    // '[' and ']' are purely program state constructs.
    /*
    /// [ : If the value at the current cell is zero, skips to the
    /// corresponding ']'. Otherwise, move to the next instruction.
    fn while_lhs (&mut self) {
        ()
    }
    /// ] : If the value at the current cell is zero, move to the next
    ///     instruction. Otherwise, move backwards in the instructions
    ///     to the corresponding '[' .
    fn while_rhs (&mut self) {
        ()
    }
    */
}

mod test {
    use super::*;
    #[test]
    fn vm_test_in_out () {
        let mut vm = VMState::new();
        let in_val:u8 = 123;
        vm.std_in(in_val);
        let out_val = vm.std_out();
        assert_eq!(in_val, out_val);
    }
    #[test]
    fn vm_test_inc_val () {
        let mut vm = VMState::new();
        vm.inc_val();
        assert_eq!(vm.std_out(), 1);
    }
    #[test]
    fn vm_test_dec_val () {
        let mut vm = VMState::new();
        vm.stack[vm.p] = 2;
        vm.dec_val();
        assert_eq!(vm.std_out(), 1);
    }
    #[test]
    fn vm_test_underflow_val () {
        let mut vm = VMState::new();
        vm.dec_val();
        assert_eq!(vm.std_out(), 255);
    }
    #[test]
    fn vm_test_overflow_val () {
        let mut vm = VMState::new();
        vm.stack[vm.p] = 255;
        vm.inc_val();
        assert_eq!(vm.std_out(), 0);
    }
    #[test]
    fn vm_test_inc_ptr () {
        let mut vm = VMState::new();
        vm.stack[0] = 0;
        vm.stack[1] = 1;
        vm.stack[2] = 2;
        vm.stack[3] = 3;
        vm.inc_ptr();
        assert_eq!(vm.std_out(), 1);
        vm.inc_ptr();
        assert_eq!(vm.std_out(), 2);
        vm.inc_ptr();
        assert_eq!(vm.std_out(), 3);
    }
    #[test]
    fn vm_test_dec_ptr () {
        let mut vm = VMState::new();
        vm.stack[0] = 0;
        vm.stack[1] = 1;
        vm.stack[2] = 2;
        vm.stack[3] = 3;
        vm.p = 3;
        vm.dec_ptr();
        assert_eq!(vm.std_out(), 2);
        vm.dec_ptr();
        assert_eq!(vm.std_out(), 1);
        vm.dec_ptr();
        assert_eq!(vm.std_out(), 0);
    }
}
<commit_msg>changed the in/out instructions to load/store to make them more congruent to instruction set terms. Also added stack over/under-flow tests.<commit_after>/// Brainfuck is represented by an array with 30,000 cells initialized to zero
/// and a data pointer pointing at the current cell.
///
/// There are eight commands:
/// + : Increments the value at the current cell by one.
/// - : Decrements the value at the current cell by one.
/// > : Moves the data pointer to the next cell (cell on the right).
/// < : Moves the data pointer to the previous cell (cell on the left).
/// . : Prints the ASCII value at the current cell (i.e. 65 = 'A').
/// , : Reads a single input character into the current cell.
/// [ : If the value at the current cell is zero, skips to the
///     corresponding ] . Otherwise, move to the next instruction.
/// ] : If the value at the current cell is zero, move to the next instruction.
///     Otherwise, move backwards in the instructions to the corresponding [ .
///
/// Note: the previous descriptions are according to the def'n of the spec.
///       Implementation specific descriptions are with the corresponding fns.
pub struct VMState {
    stack : [u8; 30000],
    p : usize,
}
impl VMState {
    pub fn new () -> VMState {
        VMState {
            stack : [0; 30000],
            p : 0
        }
    }
    /// '+' : Increments the value at the current cell by one.
    fn inc_val (&mut self) {
        self.stack[self.p] = self.stack[self.p].wrapping_add(1);
    }
    /// '-' : Decrements the value at the current cell by one.
    fn dec_val (&mut self) {
        self.stack[self.p] = self.stack[self.p].wrapping_sub(1);
    }
    /// '>' : Moves the data pointer to the next cell (cell on the right).
    fn inc_ptr (&mut self) {
        if ( self.p < (30_000-1) ) { self.p += 1; }
        else { panic!("stack overflow"); }
    }
    /// '<' : Moves the data pointer to the previous cell (cell on the left).
    fn dec_ptr (&mut self) {
        if ( self.p > 0 ) { self.p -= 1; }
        else { panic!("stack underflow"); }
    }
    /// '.' : Stores (returns) the ASCII value as a u8 at the current cell
    ///       to an external source (i.e. 65 = 'A').
    fn store (&mut self) -> u8 {
        return (self.stack[self.p]);
    }
    /// ',' : Loads (reads) a single input character into the current cell.
    fn load (&mut self, input:u8) {
        self.stack[self.p] = input;
    }
    // '[' and ']' are purely program state constructs.
    /*
    /// [ : If the value at the current cell is zero, skips to the
    /// corresponding ']'. Otherwise, move to the next instruction.
    fn while_lhs (&mut self) {
        ()
    }
    /// ] : If the value at the current cell is zero, move to the next
    ///     instruction. Otherwise, move backwards in the instructions
    ///     to the corresponding '[' .
    fn while_rhs (&mut self) {
        ()
    }
    */
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn vm_test_in_out () {
        let mut vm = VMState::new();
        let in_val:u8 = 123;
        vm.load(in_val);
        let out_val = vm.store();
        assert_eq!(in_val, out_val);
    }
    #[test]
    fn vm_test_inc_val () {
        let mut vm = VMState::new();
        vm.inc_val();
        assert_eq!(vm.store(), 1);
    }
    #[test]
    fn vm_test_dec_val () {
        let mut vm = VMState::new();
        vm.stack[vm.p] = 2;
        vm.dec_val();
        assert_eq!(vm.store(), 1);
    }
    #[test]
    fn vm_test_underflow_val () {
        let mut vm = VMState::new();
        vm.dec_val();
        assert_eq!(vm.store(), 255);
    }
    #[test]
    fn vm_test_overflow_val () {
        let mut vm = VMState::new();
        vm.stack[vm.p] = 255;
        vm.inc_val();
        assert_eq!(vm.store(), 0);
    }
    #[test]
    fn vm_test_inc_ptr () {
        let mut vm = VMState::new();
        vm.stack[0] = 0;
        vm.stack[1] = 1;
        vm.stack[2] = 2;
        vm.stack[3] = 3;
        vm.inc_ptr();
        assert_eq!(vm.store(), 1);
        vm.inc_ptr();
        assert_eq!(vm.store(), 2);
        vm.inc_ptr();
        assert_eq!(vm.store(), 3);
    }
    #[test]
    fn vm_test_dec_ptr () {
        let mut vm = VMState::new();
        vm.stack[0] = 0;
        vm.stack[1] = 1;
        vm.stack[2] = 2;
        vm.stack[3] = 3;
        vm.p = 3;
        vm.dec_ptr();
        assert_eq!(vm.store(), 2);
        vm.dec_ptr();
        assert_eq!(vm.store(), 1);
        vm.dec_ptr();
        assert_eq!(vm.store(), 0);
    }
    #[test]
    #[should_panic(expected = "stack overflow")]
    fn vm_test_stack_overflow () {
        let mut vm = VMState::new();
        vm.p = 29999;
        vm.inc_ptr();
    }
    #[test]
    #[should_panic(expected = "stack underflow")]
    fn vm_test_stack_underflow () {
        let mut vm = VMState::new();
        vm.dec_ptr();
    }
}
<|endoftext|>


<commit_before>#![crate_id="sdl2_image#sdl2_image:0.1"]
#![crate_type = "lib"]
#![desc = "SDL2_image bindings and wrappers"]
#![comment = "SDL2_image bindings and wrappers"]
#![license = "MIT"]

extern crate sdl2;
extern crate libc;

use libc::{c_int, c_char};
use std::ptr;
use sdl2::surface::Surface;
use sdl2::render::Texture;
use sdl2::render::Renderer;
use sdl2::rwops::RWops;
use sdl2::version::Version;
use sdl2::get_error;

// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link(kind="framework", name="SDL2_image")]
    extern {}

    #[cfg(not(mac_framework))]
    #[link(name="SDL2_image")]
    extern {}
}

#[cfg(target_os="win32")]
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
mod others {
    #[link(name="SDL2_image")]
    extern {}
}

#[allow(non_camel_case_types, dead_code)]
mod ffi;

/// InitFlags are passed to init() to control which subsystem
/// functionality to load.
// repr(C) "makes the size of the enum's discriminant the default
// size of enums that the C ABI for the platform uses."
#[repr(C)]
#[deriving(Clone, Eq, Hash, Show)]
pub enum InitFlag {
    InitJpg = ffi::IMG_INIT_JPG as int,
    InitPng = ffi::IMG_INIT_PNG as int,
    InitTif = ffi::IMG_INIT_TIF as int,
    InitWebp = ffi::IMG_INIT_WEBP as int,
}

/// Static method extensions for creating Surfaces
pub trait LoadSurface {
    // Self is only returned here to type hint to the compiler.
    // The syntax for type hinting in this case is not yet defined.
    // The intended return value is Result<~Surface, ~str>.
    fn from_file(filename: &Path) -> Result<~Self, ~str>;
    fn from_xpm_array(xpm: **i8) -> Result<~Self, ~str>;
}

/// Method extensions to Surface for saving to disk
pub trait SaveSurface {
    fn save(&self, filename: &Path) -> Result<(), ~str>;
    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str>;
}

impl LoadSurface for Surface {
    fn from_file(filename: &Path) -> Result<~Surface, ~str> {
        //! Loads an SDL Surface from a file
        unsafe {
            let raw = ffi::IMG_Load(filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Surface { raw: raw, owned: true })
            }
        }
    }

    fn from_xpm_array(xpm: **i8) -> Result<~Surface, ~str> {
        //! Loads an SDL Surface from XPM data
        unsafe {
            let raw = ffi::IMG_ReadXPMFromArray(xpm as **c_char);
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Surface { raw: raw, owned: true })
            }
        }
    }
}

impl SaveSurface for Surface {
    fn save(&self, filename: &Path) -> Result<(), ~str> {
        //! Saves an SDL Surface to a file
        unsafe {
            let status = ffi::IMG_SavePNG(self.raw,
                                          filename.to_c_str().unwrap());
            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }

    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str> {
        //! Saves an SDL Surface to an RWops
        unsafe {
            let status = ffi::IMG_SavePNG_RW(self.raw, dst.raw, 0);

            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }
}

/// Method extensions for creating Textures from a Renderer
pub trait LoadTexture {
    fn load_texture(&self, filename: &Path) -> Result<~Texture, ~str>;
}

impl LoadTexture for Renderer {
    fn load_texture(&self, filename: &Path) -> Result<~Texture, ~str> {
        //! Loads an SDL Texture from a file
        unsafe {
            let raw = ffi::IMG_LoadTexture(self.raw,
                                           filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Texture{ raw: raw, owned: true })
            }
        }
    }
}

pub fn init(flags: &[InitFlag]) -> ~[InitFlag] {
    //! Initializes SDL2_image with InitFlags and returns which
    //! InitFlags were actually used.
    let mut used = ~[];
    unsafe {
        let used_flags = ffi::IMG_Init(
            flags.iter().fold(0, |flags, &flag| {
                flags | flag as ffi::IMG_InitFlags
            })
        );
        for flag in flags.iter() {
            if used_flags & *flag as c_int != 0 {
                used.push(*flag)
            }
        }
    }
    used
}

pub fn quit() {
    //! Teardown the SDL2_Image subsystem
    unsafe { ffi::IMG_Quit(); }
}

pub fn get_linked_version() -> Version {
    //! Returns the version of the dynamically linked SDL_image library
    unsafe {
        Version::from_ll(ffi::IMG_Linked_Version())
    }
}

#[inline]
fn to_surface_result(raw: *sdl2::surface::ll::SDL_Surface) -> Result<~Surface, ~str> {
    if raw == ptr::null() {
        Err(get_error())
    } else {
        Ok(~Surface { raw: raw, owned: true })
    }
}

pub trait ImageRWops {
    /// load as a surface. except TGA
    fn load(&self) -> Result<~Surface, ~str>;
    /// load as a surface. This can load all supported image formats.
    fn load_typed(&self, _type: &str) -> Result<~Surface, ~str>;

    fn load_cur(&self) -> Result<~Surface, ~str>;
    fn load_ico(&self) -> Result<~Surface, ~str>;
    fn load_bmp(&self) -> Result<~Surface, ~str>;
    fn load_pnm(&self) -> Result<~Surface, ~str>;
    fn load_xpm(&self) -> Result<~Surface, ~str>;
    fn load_xcf(&self) -> Result<~Surface, ~str>;
    fn load_pcx(&self) -> Result<~Surface, ~str>;
    fn load_gif(&self) -> Result<~Surface, ~str>;
    fn load_jpg(&self) -> Result<~Surface, ~str>;
    fn load_tif(&self) -> Result<~Surface, ~str>;
    fn load_png(&self) -> Result<~Surface, ~str>;
    fn load_tga(&self) -> Result<~Surface, ~str>;
    fn load_lbm(&self) -> Result<~Surface, ~str>;
    fn load_xv(&self)  -> Result<~Surface, ~str>;
    fn load_webp(&self) -> Result<~Surface, ~str>;

    fn is_cur(&self) -> bool;
    fn is_ico(&self) -> bool;
    fn is_bmp(&self) -> bool;
    fn is_pnm(&self) -> bool;
    fn is_xpm(&self) -> bool;
    fn is_xcf(&self) -> bool;
    fn is_pcx(&self) -> bool;
    fn is_gif(&self) -> bool;
    fn is_jpg(&self) -> bool;
    fn is_tif(&self) -> bool;
    fn is_png(&self) -> bool;
    fn is_lbm(&self) -> bool;
    fn is_xv(&self)  -> bool;
    fn is_webp(&self) -> bool;
}

impl ImageRWops for RWops {
    fn load(&self) -> Result<~Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_Load_RW(self.raw, 0)
        };
        to_surface_result(raw)
    }
    fn load_typed(&self, _type: &str) -> Result<~Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_LoadTyped_RW(self.raw, 0, _type.to_c_str().unwrap())
        };
        to_surface_result(raw)
    }

    fn load_cur(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadCUR_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_ico(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadICO_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_bmp(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadBMP_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pnm(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xpm(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXPM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xcf(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXCF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pcx(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPCX_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_gif(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadGIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_jpg(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadJPG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tif(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_png(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tga(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTGA_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_lbm(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadLBM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xv(&self)  -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXV_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_webp(&self)  -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadWEBP_RW(self.raw) };
        to_surface_result(raw)
    }

    fn is_cur(&self) -> bool {
        unsafe { ffi::IMG_isCUR(self.raw) == 1 }
    }
    fn is_ico(&self) -> bool {
        unsafe { ffi::IMG_isICO(self.raw) == 1 }
    }
    fn is_bmp(&self) -> bool {
        unsafe { ffi::IMG_isBMP(self.raw) == 1 }
    }
    fn is_pnm(&self) -> bool {
        unsafe { ffi::IMG_isPNM(self.raw) == 1 }
    }
    fn is_xpm(&self) -> bool {
        unsafe { ffi::IMG_isXPM(self.raw) == 1 }
    }
    fn is_xcf(&self) -> bool {
        unsafe { ffi::IMG_isXCF(self.raw) == 1 }
    }
    fn is_pcx(&self) -> bool {
        unsafe { ffi::IMG_isPCX(self.raw) == 1 }
    }
    fn is_gif(&self) -> bool {
        unsafe { ffi::IMG_isGIF(self.raw) == 1 }
    }
    fn is_jpg(&self) -> bool {
        unsafe { ffi::IMG_isJPG(self.raw) == 1 }
    }
    fn is_tif(&self) -> bool {
        unsafe { ffi::IMG_isTIF(self.raw) == 1 }
    }
    fn is_png(&self) -> bool {
        unsafe { ffi::IMG_isPNG(self.raw) == 1 }
    }
    fn is_lbm(&self) -> bool {
        unsafe { ffi::IMG_isLBM(self.raw) == 1 }
    }
    fn is_xv(&self)  -> bool {
        unsafe { ffi::IMG_isXV(self.raw)  == 1 }
    }
    fn is_webp(&self) -> bool {
        unsafe { ffi::IMG_isWEBP(self.raw)  == 1 }
    }
}
<commit_msg>fix compile error: owned vector ~[] now immutable<commit_after>#![crate_id="sdl2_image#sdl2_image:0.1"]
#![crate_type = "lib"]
#![desc = "SDL2_image bindings and wrappers"]
#![comment = "SDL2_image bindings and wrappers"]
#![license = "MIT"]

extern crate sdl2;
extern crate libc;

use libc::{c_int, c_char};
use std::ptr;
use sdl2::surface::Surface;
use sdl2::render::Texture;
use sdl2::render::Renderer;
use sdl2::rwops::RWops;
use sdl2::version::Version;
use sdl2::get_error;

// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link(kind="framework", name="SDL2_image")]
    extern {}

    #[cfg(not(mac_framework))]
    #[link(name="SDL2_image")]
    extern {}
}

#[cfg(target_os="win32")]
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
mod others {
    #[link(name="SDL2_image")]
    extern {}
}

#[allow(non_camel_case_types, dead_code)]
mod ffi;

/// InitFlags are passed to init() to control which subsystem
/// functionality to load.
// repr(C) "makes the size of the enum's discriminant the default
// size of enums that the C ABI for the platform uses."
#[repr(C)]
#[deriving(Clone, Eq, Hash, Show)]
pub enum InitFlag {
    InitJpg = ffi::IMG_INIT_JPG as int,
    InitPng = ffi::IMG_INIT_PNG as int,
    InitTif = ffi::IMG_INIT_TIF as int,
    InitWebp = ffi::IMG_INIT_WEBP as int,
}

/// Static method extensions for creating Surfaces
pub trait LoadSurface {
    // Self is only returned here to type hint to the compiler.
    // The syntax for type hinting in this case is not yet defined.
    // The intended return value is Result<~Surface, ~str>.
    fn from_file(filename: &Path) -> Result<~Self, ~str>;
    fn from_xpm_array(xpm: **i8) -> Result<~Self, ~str>;
}

/// Method extensions to Surface for saving to disk
pub trait SaveSurface {
    fn save(&self, filename: &Path) -> Result<(), ~str>;
    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str>;
}

impl LoadSurface for Surface {
    fn from_file(filename: &Path) -> Result<~Surface, ~str> {
        //! Loads an SDL Surface from a file
        unsafe {
            let raw = ffi::IMG_Load(filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Surface { raw: raw, owned: true })
            }
        }
    }

    fn from_xpm_array(xpm: **i8) -> Result<~Surface, ~str> {
        //! Loads an SDL Surface from XPM data
        unsafe {
            let raw = ffi::IMG_ReadXPMFromArray(xpm as **c_char);
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Surface { raw: raw, owned: true })
            }
        }
    }
}

impl SaveSurface for Surface {
    fn save(&self, filename: &Path) -> Result<(), ~str> {
        //! Saves an SDL Surface to a file
        unsafe {
            let status = ffi::IMG_SavePNG(self.raw,
                                          filename.to_c_str().unwrap());
            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }

    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str> {
        //! Saves an SDL Surface to an RWops
        unsafe {
            let status = ffi::IMG_SavePNG_RW(self.raw, dst.raw, 0);

            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }
}

/// Method extensions for creating Textures from a Renderer
pub trait LoadTexture {
    fn load_texture(&self, filename: &Path) -> Result<~Texture, ~str>;
}

impl LoadTexture for Renderer {
    fn load_texture(&self, filename: &Path) -> Result<~Texture, ~str> {
        //! Loads an SDL Texture from a file
        unsafe {
            let raw = ffi::IMG_LoadTexture(self.raw,
                                           filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Texture{ raw: raw, owned: true })
            }
        }
    }
}

pub fn init(flags: &[InitFlag]) -> ~[InitFlag] {
    //! Initializes SDL2_image with InitFlags and returns which
    //! InitFlags were actually used.
    let mut used = Vec::new();
    unsafe {
        let used_flags = ffi::IMG_Init(
            flags.iter().fold(0, |flags, &flag| {
                flags | flag as ffi::IMG_InitFlags
            })
        );
        for flag in flags.iter() {
            if used_flags & *flag as c_int != 0 {
                used.push(*flag)
            }
        }
    }
    used.as_slice().into_owned()
}

pub fn quit() {
    //! Teardown the SDL2_Image subsystem
    unsafe { ffi::IMG_Quit(); }
}

pub fn get_linked_version() -> Version {
    //! Returns the version of the dynamically linked SDL_image library
    unsafe {
        Version::from_ll(ffi::IMG_Linked_Version())
    }
}

#[inline]
fn to_surface_result(raw: *sdl2::surface::ll::SDL_Surface) -> Result<~Surface, ~str> {
    if raw == ptr::null() {
        Err(get_error())
    } else {
        Ok(~Surface { raw: raw, owned: true })
    }
}

pub trait ImageRWops {
    /// load as a surface. except TGA
    fn load(&self) -> Result<~Surface, ~str>;
    /// load as a surface. This can load all supported image formats.
    fn load_typed(&self, _type: &str) -> Result<~Surface, ~str>;

    fn load_cur(&self) -> Result<~Surface, ~str>;
    fn load_ico(&self) -> Result<~Surface, ~str>;
    fn load_bmp(&self) -> Result<~Surface, ~str>;
    fn load_pnm(&self) -> Result<~Surface, ~str>;
    fn load_xpm(&self) -> Result<~Surface, ~str>;
    fn load_xcf(&self) -> Result<~Surface, ~str>;
    fn load_pcx(&self) -> Result<~Surface, ~str>;
    fn load_gif(&self) -> Result<~Surface, ~str>;
    fn load_jpg(&self) -> Result<~Surface, ~str>;
    fn load_tif(&self) -> Result<~Surface, ~str>;
    fn load_png(&self) -> Result<~Surface, ~str>;
    fn load_tga(&self) -> Result<~Surface, ~str>;
    fn load_lbm(&self) -> Result<~Surface, ~str>;
    fn load_xv(&self)  -> Result<~Surface, ~str>;
    fn load_webp(&self) -> Result<~Surface, ~str>;

    fn is_cur(&self) -> bool;
    fn is_ico(&self) -> bool;
    fn is_bmp(&self) -> bool;
    fn is_pnm(&self) -> bool;
    fn is_xpm(&self) -> bool;
    fn is_xcf(&self) -> bool;
    fn is_pcx(&self) -> bool;
    fn is_gif(&self) -> bool;
    fn is_jpg(&self) -> bool;
    fn is_tif(&self) -> bool;
    fn is_png(&self) -> bool;
    fn is_lbm(&self) -> bool;
    fn is_xv(&self)  -> bool;
    fn is_webp(&self) -> bool;
}

impl ImageRWops for RWops {
    fn load(&self) -> Result<~Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_Load_RW(self.raw, 0)
        };
        to_surface_result(raw)
    }
    fn load_typed(&self, _type: &str) -> Result<~Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_LoadTyped_RW(self.raw, 0, _type.to_c_str().unwrap())
        };
        to_surface_result(raw)
    }

    fn load_cur(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadCUR_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_ico(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadICO_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_bmp(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadBMP_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pnm(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xpm(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXPM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xcf(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXCF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pcx(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPCX_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_gif(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadGIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_jpg(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadJPG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tif(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_png(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tga(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTGA_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_lbm(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadLBM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xv(&self)  -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXV_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_webp(&self)  -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadWEBP_RW(self.raw) };
        to_surface_result(raw)
    }

    fn is_cur(&self) -> bool {
        unsafe { ffi::IMG_isCUR(self.raw) == 1 }
    }
    fn is_ico(&self) -> bool {
        unsafe { ffi::IMG_isICO(self.raw) == 1 }
    }
    fn is_bmp(&self) -> bool {
        unsafe { ffi::IMG_isBMP(self.raw) == 1 }
    }
    fn is_pnm(&self) -> bool {
        unsafe { ffi::IMG_isPNM(self.raw) == 1 }
    }
    fn is_xpm(&self) -> bool {
        unsafe { ffi::IMG_isXPM(self.raw) == 1 }
    }
    fn is_xcf(&self) -> bool {
        unsafe { ffi::IMG_isXCF(self.raw) == 1 }
    }
    fn is_pcx(&self) -> bool {
        unsafe { ffi::IMG_isPCX(self.raw) == 1 }
    }
    fn is_gif(&self) -> bool {
        unsafe { ffi::IMG_isGIF(self.raw) == 1 }
    }
    fn is_jpg(&self) -> bool {
        unsafe { ffi::IMG_isJPG(self.raw) == 1 }
    }
    fn is_tif(&self) -> bool {
        unsafe { ffi::IMG_isTIF(self.raw) == 1 }
    }
    fn is_png(&self) -> bool {
        unsafe { ffi::IMG_isPNG(self.raw) == 1 }
    }
    fn is_lbm(&self) -> bool {
        unsafe { ffi::IMG_isLBM(self.raw) == 1 }
    }
    fn is_xv(&self)  -> bool {
        unsafe { ffi::IMG_isXV(self.raw)  == 1 }
    }
    fn is_webp(&self) -> bool {
        unsafe { ffi::IMG_isWEBP(self.raw)  == 1 }
    }
}
<|endoftext|>