Skip to main content

laminar_db/ffi/
memory.rs

1//! FFI memory management functions.
2
3use std::ffi::{c_char, CString};
4
5/// Transfer ownership of a `CString` to a raw pointer; free with `laminar_string_free`.
6pub(crate) fn take_ownership_string(s: CString) -> *mut c_char {
7    s.into_raw()
8}
9
10/// Free a string allocated by a laminar function.
11///
12/// # Safety
13///
14/// `s` must be a pointer returned by a laminar function, or NULL.
15#[no_mangle]
16pub unsafe extern "C" fn laminar_string_free(s: *mut c_char) {
17    if !s.is_null() {
18        drop(unsafe { CString::from_raw(s) });
19    }
20}
21
22/// Return the library version as a static null-terminated string (do not free).
23///
24/// # Safety
25///
26/// The returned pointer is valid for the lifetime of the process.
27#[no_mangle]
28pub extern "C" fn laminar_version() -> *const c_char {
29    static VERSION: &[u8] = concat!(env!("CARGO_PKG_VERSION"), "\0").as_bytes();
30    VERSION.as_ptr().cast()
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36    use std::ffi::CStr;
37
38    #[test]
39    fn test_string_free_null() {
40        // Should not crash
41        // SAFETY: Testing null handling
42        unsafe {
43            laminar_string_free(std::ptr::null_mut());
44        }
45    }
46
47    #[test]
48    fn test_string_round_trip() {
49        let original = "Hello, FFI!";
50        let c_string = CString::new(original).unwrap();
51        let ptr = take_ownership_string(c_string);
52
53        // SAFETY: ptr was just created
54        let retrieved = unsafe { CStr::from_ptr(ptr).to_str().unwrap() };
55        assert_eq!(retrieved, original);
56
57        // SAFETY: ptr is valid
58        unsafe { laminar_string_free(ptr) };
59    }
60
61    #[test]
62    fn test_version() {
63        let ptr = laminar_version();
64        assert!(!ptr.is_null());
65
66        // SAFETY: ptr points to a static string
67        let version = unsafe { CStr::from_ptr(ptr).to_str().unwrap() };
68        assert!(!version.is_empty());
69        // Should contain version number pattern
70        assert!(version.chars().any(|c| c.is_ascii_digit()));
71    }
72}