X-Git-Url: https://piware.de/gitweb/?p=learn-rust.git;a=blobdiff_plain;f=call-rust-from-c%2Fsrc%2Flib.rs;h=6a87bea780743861980f7d615fe53ac0ca0a5f45;hp=f5e43842b908f49ffbbe5e3799f75156aa186521;hb=8c240f514e17c9a935f5f392e6a87779ae1c09e8;hpb=7ed2d982ac15df78e852fd5835d137881536a4ef diff --git a/call-rust-from-c/src/lib.rs b/call-rust-from-c/src/lib.rs index f5e4384..6a87bea 100644 --- a/call-rust-from-c/src/lib.rs +++ b/call-rust-from-c/src/lib.rs @@ -1,3 +1,4 @@ +use std::ffi::{CStr, CString}; use std::os::raw; /// Return The Answer. @@ -14,6 +15,54 @@ pub extern "C" fn answer() -> raw::c_int { return 42; } +#[no_mangle] +pub extern "C" fn r_strlen(s: *const raw::c_char) -> usize { + unsafe { CStr::from_ptr(s) }.to_bytes().len() +} + +/// Return a vector of pointers as C pointer array +/// +/// The memory of `vec` gets leaked, as otherwise Rust would free it once the vector +/// goes out of scope, and C would access invalid memory. +fn return_c_vec(mut vec: Vec) -> *mut T { + let p = vec.as_mut_ptr(); + // unref vector so that it does not get freed when going out of scope + std::mem::forget(vec); + p +} + +#[no_mangle] +pub extern "C" fn r_strlist() -> *mut *const raw::c_uchar { + let v = vec![ + "Hello\0".as_ptr(), + "World\0".as_ptr() + ]; + return_c_vec(v) +} + +fn impl_grep<'a>(needle: &str, haystack: &'a str) -> Vec<&'a str> { + haystack.lines() + .filter(|line| line.contains(needle)) + .collect() +} + +#[no_mangle] +pub extern "C" fn r_grep(needle: *const raw::c_char, haystack: *const raw::c_char) -> *mut *const raw::c_char { + let haystack_cstr = unsafe { CStr::from_ptr(haystack).to_str() }.unwrap(); + let strvec = impl_grep(unsafe { CStr::from_ptr(needle).to_str().unwrap() }, haystack_cstr); + + // Vec[str] -> Vec[const char*] + let p_vec: Vec<_> = strvec.into_iter() + .map(|s| { + let s = CString::new(s).unwrap(); + let p = s.as_ptr(); + std::mem::forget(s); + p + }) + .collect(); + + return_c_vec(p_vec) +} #[cfg(test)] mod tests { @@ -23,4 +72,9 @@ mod tests { fn test_answer() { assert_eq!(answer(), 42); } + + #[test] + fn test_grep() { + assert_eq!(impl_grep("ell", "Hello\nworld\ncan you tell?"), vec!["Hello", "can you tell?"]); + } }