1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use std::ffi::{CStr, CString};
use std::ptr;
use std::slice;

use binding::global::{RubySpecialConsts, rb_cObject};
use binding::class::const_get;
use binding::vm;
use types::{c_char, c_int, c_void, Argc, InternalValue, Value};

use {AnyObject, Object, Boolean};
use crate::rubysys::rproc::{
    rb_obj_is_proc,
    rb_obj_is_method,
};

pub unsafe fn cstr_to_string(str: *const c_char) -> String {
    CStr::from_ptr(str).to_string_lossy().into_owned()
}

pub unsafe fn cstr_to_str<'a>(str: *const c_char) -> &'a str {
    CStr::from_ptr(str).to_str().unwrap()
}

pub fn str_to_cstring(str: &str) -> CString {
    CString::new(str).unwrap()
}

pub fn bool_to_value(state: bool) -> Value {
    let internal_value = if state {
        RubySpecialConsts::True
    } else {
        RubySpecialConsts::False
    };

    Value::from(internal_value as InternalValue)
}

#[inline]
pub fn c_int_to_bool(int: c_int) -> bool {
    int != 0
}

#[inline]
pub fn bool_to_c_int(state: bool) -> c_int {
    state as c_int
}

pub fn arguments_to_values(arguments: &[AnyObject]) -> Vec<Value> {
    arguments.as_ref().iter().map(Object::value).collect()
}

pub fn process_arguments(arguments: &[Value]) -> (Argc, *const Value) {
    (arguments.len() as Argc, arguments.as_ptr())
}

pub fn option_to_slice<'a, T>(option: &'a Option<T>) -> &'a [T] {
    match option {
        &Some(ref v) => unsafe { slice::from_raw_parts(v, 1) },
        &None => &[],
    }
}

// Converts a pointer to array of `AnyObject`s to `Vec<AnyObject>`.
//
// This function is a helper for callbacks, do not use it directly.
//
// It will be moved to other struct, because it is not related to VM itself.
//
// # Examples
//
// ```no_run
// use rutie::types::Argc;
// use rutie::{AnyObject, Boolean, Class, Object, RString, util};
//
// #[no_mangle]
// pub extern fn string_eq(argc: Argc, argv: *const AnyObject, rtself: RString) -> Boolean {
//     let argv = util::parse_arguments(argc, argv);
//     let other_string = argv[0].try_convert_to::<RString>().unwrap();
//
//     Boolean::new(rtself.to_str() == other_string.to_str())
// }
//
// fn main() {
//     Class::from_existing("String").define_method("==", string_eq);
// }
// ```
pub fn parse_arguments(argc: Argc, arguments: *const AnyObject) -> Vec<AnyObject> {
    unsafe { slice::from_raw_parts(arguments, argc as usize).to_vec() }
}

pub fn closure_to_ptr<F, R>(mut func: F) -> *const c_void
where
    F: FnMut() -> R,
{
    let wrap_return = move || {
        let r = func();
        Box::into_raw(Box::new(r)) as *const c_void
    };

    let fnbox = Box::new(wrap_return) as Box<dyn FnMut() -> *const c_void>;

    Box::into_raw(Box::new(fnbox)) as *const c_void
}

pub unsafe fn ptr_to_data<R>(ptr: *mut c_void) -> R {
    *Box::from_raw(ptr as *mut R)
}

pub fn is_proc(obj: Value) -> bool {
    Boolean::from(unsafe { rb_obj_is_proc(obj) }).to_bool()
}

pub fn is_method(obj: Value) -> bool {
    Boolean::from(unsafe { rb_obj_is_method(obj) }).to_bool()
}

// Recurses to the deepest ruby object.
//
// Given `"A::B::C"` it will return the object instance of `C`.
pub fn inmost_rb_object(klass: &str) -> Value {
    let object = unsafe { rb_cObject };

    klass.split("::").fold(object, |acc, x| const_get(acc, x))
}

pub mod callback_call {
    use ::types::{c_void, CallbackMutPtr, st_retval};

    pub fn no_parameters<F: FnMut() -> R, R>(ptr: CallbackMutPtr) -> R {
        let f = ptr as *mut F;
        unsafe { (*f)() }
    }

    pub fn one_parameter<F: FnMut(A) -> R, A, R>(a: A, ptr: CallbackMutPtr) -> R {
        let f = ptr as *mut F;
        unsafe { (*f)(a) }
    }

    pub fn hash_foreach_callback<F: FnMut(A, B), A, B>(a: A, b: B, ptr: CallbackMutPtr) -> st_retval {
        let f = ptr as *mut F;
        unsafe { (*f)(a, b); }
        st_retval::Continue
    }
}