nix_bindings_util/
string_return.rs1use anyhow::Result;
2
3pub unsafe extern "C" fn callback_get_result_string(
15 start: *const ::std::os::raw::c_char,
16 n: std::os::raw::c_uint,
17 user_data: *mut std::os::raw::c_void,
18) {
19 let ret = user_data as *mut Result<String>;
20
21 if start.is_null() {
22 if n != 0 {
23 panic!("callback_get_result_string: start is null but n is not zero");
24 }
25 *ret = Ok(String::new());
26 return;
27 }
28
29 let slice = std::slice::from_raw_parts(start as *const u8, n as usize);
30
31 if (*ret).is_ok() {
32 panic!(
33 "callback_get_result_string: Result must be initialized to Err. Did Nix call us twice?"
34 );
35 }
36
37 *ret = String::from_utf8(slice.to_vec())
38 .map_err(|e| anyhow::format_err!("Nix string is not valid UTF-8: {}", e));
39}
40
41pub fn callback_get_result_string_data(vec: &mut Result<String>) -> *mut std::os::raw::c_void {
42 vec as *mut Result<String> as *mut std::os::raw::c_void
43}
44
45#[macro_export]
46macro_rules! result_string_init {
47 () => {
48 Err(anyhow::anyhow!("String was not set by Nix C API"))
49 };
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use nix_bindings_util_sys as raw;
56
57 static _CALLBACK_GET_RESULT_STRING: raw::get_string_callback = Some(callback_get_result_string);
59
60 #[test]
61 fn test_callback_get_result_string_empty() {
62 let mut ret: Result<String> = result_string_init!();
63 let start: *const std::os::raw::c_char = std::ptr::null();
64 let n: std::os::raw::c_uint = 0;
65 let user_data: *mut std::os::raw::c_void = callback_get_result_string_data(&mut ret);
66
67 unsafe {
68 callback_get_result_string(start, n, user_data);
69 }
70
71 let s = ret.unwrap();
72 assert_eq!(s, "");
73 }
74
75 #[test]
76 fn test_callback_result_string() {
77 let mut ret: Result<String> = result_string_init!();
78 let start = b"helloGARBAGE".as_ptr() as *const std::os::raw::c_char;
79 let n: std::os::raw::c_uint = 5;
80 let user_data: *mut std::os::raw::c_void = callback_get_result_string_data(&mut ret);
81 unsafe {
82 callback_get_result_string(start, n, user_data);
83 }
84
85 let s = ret.unwrap();
86 assert_eq!(s, "hello");
87 }
88}