Skip to main content

diffsol_c/
string_c.rs

1use std::alloc::{Layout, alloc, dealloc};
2use std::ffi::c_char;
3
4/// Allocate memory for a string of given size (including null terminator)
5/// Returns a pointer to writable memory that TypeScript can write to
6///
7/// # Safety
8/// The returned pointer must be released with `diffsol_free_string` using the
9/// same `size`. The caller must not read or write beyond the allocated buffer.
10#[unsafe(no_mangle)]
11pub unsafe extern "C" fn diffsol_alloc_string(size: usize) -> *mut c_char {
12    if size == 0 {
13        return std::ptr::null_mut();
14    }
15
16    // Create a Vec with the requested capacity and length
17    let mut buffer = vec![0u8; size];
18    let ptr = buffer.as_mut_ptr();
19    std::mem::forget(buffer); // Prevent the Vec from being dropped
20
21    ptr as *mut c_char
22}
23
24/// Allocate aligned memory for arbitrary data
25///
26/// # Safety
27/// The returned pointer must be released with `diffsol_free` using the same
28/// `size` and `align`. `align` must be a valid alignment value.
29#[unsafe(no_mangle)]
30pub unsafe extern "C" fn diffsol_alloc(size: usize, align: usize) -> *mut u8 {
31    if size == 0 {
32        return std::ptr::null_mut();
33    }
34    let align = if align == 0 { 1 } else { align };
35    let layout = match Layout::from_size_align(size, align) {
36        Ok(layout) => layout,
37        Err(_) => return std::ptr::null_mut(),
38    };
39    let ptr = unsafe { alloc(layout) };
40    if ptr.is_null() {
41        return std::ptr::null_mut();
42    }
43    ptr
44}
45
46/// Free aligned memory allocated by diffsol_alloc
47///
48/// # Safety
49/// `ptr` must be either null or a pointer returned by `diffsol_alloc` with the
50/// same `size` and `align` values.
51#[unsafe(no_mangle)]
52pub unsafe extern "C" fn diffsol_free(ptr: *mut u8, size: usize, align: usize) {
53    if ptr.is_null() || size == 0 {
54        return;
55    }
56    let align = if align == 0 { 1 } else { align };
57    let layout = match Layout::from_size_align(size, align) {
58        Ok(layout) => layout,
59        Err(_) => return,
60    };
61    unsafe { dealloc(ptr, layout) };
62}
63
64/// Free memory allocated by diffsol_alloc_string
65///
66/// # Safety
67/// `ptr` must be either null or a pointer returned by `diffsol_alloc_string`
68/// with the same `size`.
69#[unsafe(no_mangle)]
70pub unsafe extern "C" fn diffsol_free_string(ptr: *mut c_char, size: usize) {
71    if ptr.is_null() || size == 0 {
72        return;
73    }
74
75    // Reconstruct the Vec from the raw pointer and drop it
76    let _ = unsafe { Vec::from_raw_parts(ptr as *mut u8, size, size) };
77    // Vec will be dropped here, freeing the memory
78}