2024-05-22 14:45:12 +02:00
use anyhow ::Result ;
2024-04-04 15:24:31 +02:00
/// Callback for nix_store_get_uri and other functions that return a string.
///
/// This function is used by the other nix_* crates, and you should never need to call it yourself.
2024-05-09 12:41:34 -04:00
///
/// Some functions in the nix library "return" strings without giving you ownership over them, by letting you pass a callback function that gets to look at that string. This callback simply turns that string pointer into an owned rust String.
2024-11-27 10:26:39 +01:00
///
/// # Safety
///
/// _Manual memory management_
///
/// Only for passing to the nix C API. Do not call this function directly.
2024-05-22 14:45:12 +02:00
pub unsafe extern " C " fn callback_get_result_string (
2024-04-04 15:24:31 +02:00
start : * const ::std ::os ::raw ::c_char ,
n : std ::os ::raw ::c_uint ,
user_data : * mut std ::os ::raw ::c_void ,
) {
2024-05-22 14:45:12 +02:00
let ret = user_data as * mut Result < String > ;
2024-08-29 15:52:16 +02:00
2024-11-27 10:26:39 +01:00
if start . is_null ( ) {
2024-08-29 15:52:16 +02:00
if n ! = 0 {
panic! ( " callback_get_result_string: start is null but n is not zero " ) ;
}
* ret = Ok ( String ::new ( ) ) ;
return ;
}
2024-04-04 15:24:31 +02:00
let slice = std ::slice ::from_raw_parts ( start as * const u8 , n as usize ) ;
2024-05-22 14:45:12 +02:00
2024-11-27 10:26:39 +01:00
if ( * ret ) . is_ok ( ) {
2024-05-22 14:45:12 +02:00
panic! (
" callback_get_result_string: Result must be initialized to Err. Did Nix call us twice? "
) ;
2024-04-04 15:24:31 +02:00
}
2024-05-22 14:45:12 +02:00
* ret = String ::from_utf8 ( slice . to_vec ( ) )
. map_err ( | e | anyhow ::format_err! ( " Nix string is not valid UTF-8: {} " , e ) ) ;
2024-04-04 15:24:31 +02:00
}
2024-05-22 14:45:12 +02:00
pub fn callback_get_result_string_data ( vec : & mut Result < String > ) -> * mut std ::os ::raw ::c_void {
vec as * mut Result < String > as * mut std ::os ::raw ::c_void
}
#[ macro_export ]
macro_rules ! result_string_init {
( ) = > {
Err ( anyhow ::anyhow! ( " String was not set by Nix C API " ) )
} ;
2024-04-08 16:25:37 +02:00
}
2024-04-04 15:24:31 +02:00
#[ cfg(test) ]
mod tests {
use super ::* ;
2025-10-04 02:44:22 +02:00
use nix_bindings_bindgen_raw as raw ;
2024-04-04 15:24:31 +02:00
2025-10-04 02:44:22 +02:00
/// Typecheck the function signature against the generated bindings in nix_bindings_bindgen_raw.
2024-05-22 14:45:12 +02:00
static _CALLBACK_GET_RESULT_STRING : raw ::get_string_callback = Some ( callback_get_result_string ) ;
2024-04-04 15:24:31 +02:00
#[ test ]
2024-05-22 14:45:12 +02:00
fn test_callback_get_result_string_empty ( ) {
let mut ret : Result < String > = result_string_init! ( ) ;
2024-04-04 15:24:31 +02:00
let start : * const std ::os ::raw ::c_char = std ::ptr ::null ( ) ;
let n : std ::os ::raw ::c_uint = 0 ;
2024-05-22 14:45:12 +02:00
let user_data : * mut std ::os ::raw ::c_void = callback_get_result_string_data ( & mut ret ) ;
2024-04-04 15:24:31 +02:00
unsafe {
2024-05-22 14:45:12 +02:00
callback_get_result_string ( start , n , user_data ) ;
2024-04-04 15:24:31 +02:00
}
2024-05-22 14:45:12 +02:00
let s = ret . unwrap ( ) ;
assert_eq! ( s , " " ) ;
2024-04-04 15:24:31 +02:00
}
#[ test ]
2024-05-22 14:45:12 +02:00
fn test_callback_result_string ( ) {
let mut ret : Result < String > = result_string_init! ( ) ;
2024-04-04 15:24:31 +02:00
let start : * const std ::os ::raw ::c_char = b " helloGARBAGE " . as_ptr ( ) as * const i8 ;
let n : std ::os ::raw ::c_uint = 5 ;
2024-05-22 14:45:12 +02:00
let user_data : * mut std ::os ::raw ::c_void = callback_get_result_string_data ( & mut ret ) ;
2024-04-04 15:24:31 +02:00
unsafe {
2024-05-22 14:45:12 +02:00
callback_get_result_string ( start , n , user_data ) ;
2024-04-04 15:24:31 +02:00
}
2024-05-22 14:45:12 +02:00
let s = ret . unwrap ( ) ;
assert_eq! ( s , " hello " ) ;
2024-04-04 15:24:31 +02:00
}
}