#![deny(missing_docs)]
use std::convert::TryInto;
use std::ffi::{CStr, CString};
#[no_mangle]
pub extern "C" fn hello_world_rust_2_fn(
callback: Option<unsafe extern "C" fn(msg: *const i8) -> i32>)
-> i32
{
let callback_fn = callback.unwrap();
let msg = String::from("from Rust");
let msg_cstr = CString::new(msg).unwrap();
let ret = unsafe {
callback_fn(msg_cstr.as_ptr())
};
let str = format!(
"Hello world 2, printed in Rust, callback_fn = {:?}, ret = {ret}.",
callback_fn);
println!("{str}");
str.len().try_into().unwrap()
}
#[no_mangle]
pub extern "C" fn hello_world_rust_2_callback(msg: *const i8) -> i32
{
let cstr = unsafe {
CStr::from_ptr(msg)
};
let safe_cstr = String::from_utf8_lossy(cstr.to_bytes())
.to_string();
let str = format!(
"Hello world 2 callback, printed in Rust, {safe_cstr}.");
println!("{str}");
str.len().try_into().unwrap()
}
#[cfg(test)]
mod tests
{
use super::*;
#[test]
fn test_hello_world_rust_2_fn_success()
{
let format = "Hello world 2, printed in Rust, callback_fn = , ret = .";
let callback = hello_world_rust_2_callback;
let ret = hello_world_rust_2_fn(Some(callback));
let right_len: i32 = format.len()
.try_into()
.expect("usize to i32 conversion MUST succeed");
println!("ret = {}, right_len = {}.", ret, right_len);
assert!(ret >
format.len()
.try_into()
.expect("usize to i32 conversion MUST succeed"));
}
#[test]
#[should_panic]
fn test_hello_world_rust_2_fn_fail_null_callback()
{
hello_world_rust_2_fn(None);
}
#[test]
fn test_hello_world_rust_2_callback()
{
use std::ffi::CString;
let msg_str = String::from("called for testing");
let msg_cstr = CString::new(msg_str.clone().into_bytes())
.expect("CString creation MUST succeed");
let format = "Hello world 2 callback, printed in Rust, .";
let ret = hello_world_rust_2_callback(msg_cstr.into_raw());
assert_eq!(ret,
(format.len() + msg_str.len())
.try_into()
.expect("usize to i32 conversion MUST succeed"));
}
}