use crate::rubysys::types::{c_char, c_int, c_void, size_t, Value};
pub type EachWordsFunction =
rutie_callback!(type fn(word: *const c_char, len: c_int, argv: *mut c_void));
#[cfg_attr(rutie_dllimport, link(name = "rutie_ruby"))]
extern "C" {
pub fn rb_class2name(klass: Value) -> *const c_char;
pub fn rb_obj_classname(obj: Value) -> *const c_char;
pub fn ruby_each_words(str: *const c_char, func: EachWordsFunction, argv: *mut c_void);
pub fn ruby_snprintf(str: *mut c_char, n: size_t, fmt: *const c_char, ...) -> c_int;
pub fn ruby_strdup(str: *const c_char) -> *mut c_char;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::binding::vm;
use std::ffi::CStr;
rutie_callback! {
fn collect_word(word: *const c_char, len: c_int, argv: *mut c_void) {
let word = unsafe { std::slice::from_raw_parts(word as *const u8, len as usize) };
let words = unsafe { &mut *(argv as *mut Vec<String>) };
words.push(String::from_utf8(word.to_vec()).unwrap());
}
}
#[test]
fn test_c_strings() {
crate::on_ruby_thread(|| unsafe {
let klass = vm::eval_string("Comparable");
assert_eq!(
CStr::from_ptr(rb_class2name(klass)).to_str().unwrap(),
"Comparable"
);
let object = vm::eval_string("1.0");
assert_eq!(
CStr::from_ptr(rb_obj_classname(object)).to_str().unwrap(),
"Float"
);
let mut words: Vec<String> = Vec::new();
ruby_each_words(
b"one two,three four\0".as_ptr() as *const c_char,
collect_word,
&mut words as *mut Vec<String> as *mut c_void,
);
assert_eq!(words, ["one", "two", "three", "four"]);
let mut buffer = [0 as c_char; 32];
let written = ruby_snprintf(
buffer.as_mut_ptr(),
buffer.len(),
b"%s-%d-%.2f\0".as_ptr() as *const c_char,
b"x\0".as_ptr() as *const c_char,
42 as c_int,
1.5f64,
);
assert_eq!(written, 9);
assert_eq!(
CStr::from_ptr(buffer.as_ptr()).to_str().unwrap(),
"x-42-1.50"
);
let written = ruby_snprintf(
buffer.as_mut_ptr(),
3,
b"%s\0".as_ptr() as *const c_char,
b"abcdef\0".as_ptr() as *const c_char,
);
assert_eq!(written, 6);
assert_eq!(CStr::from_ptr(buffer.as_ptr()).to_str().unwrap(), "ab");
let copy = ruby_strdup(b"rutie\0".as_ptr() as *const c_char);
assert_eq!(CStr::from_ptr(copy).to_str().unwrap(), "rutie");
crate::rubysys::gc::ruby_xfree(copy as *mut c_void);
});
}
}