sigil_parser/ffi/
helpers.rs1use std::ffi::{CStr, CString};
9use std::os::raw::c_char;
10
11pub struct CStringOwned {
14 ptr: *mut c_char,
15 len: usize,
16}
17
18impl CStringOwned {
19 pub fn null() -> Self {
21 Self {
22 ptr: std::ptr::null_mut(),
23 len: 0,
24 }
25 }
26
27 pub fn as_ptr(&self) -> *const c_char {
29 self.ptr
30 }
31
32 pub fn as_mut_ptr(&mut self) -> *mut c_char {
34 self.ptr
35 }
36
37 pub fn is_null(&self) -> bool {
39 self.ptr.is_null()
40 }
41
42 pub fn len(&self) -> usize {
44 self.len
45 }
46
47 pub fn is_empty(&self) -> bool {
49 self.len == 0
50 }
51}
52
53impl Drop for CStringOwned {
54 fn drop(&mut self) {
55 if !self.ptr.is_null() {
56 unsafe {
57 drop(CString::from_raw(self.ptr));
59 }
60 }
61 }
62}
63
64#[no_mangle]
71pub extern "C" fn sigil_string_to_cstring(ptr: *const u8, len: usize) -> *mut c_char {
72 if ptr.is_null() || len == 0 {
73 match CString::new("") {
75 Ok(cstr) => cstr.into_raw(),
76 Err(_) => std::ptr::null_mut(),
77 }
78 } else {
79 unsafe {
80 let slice = std::slice::from_raw_parts(ptr, len);
81 match std::str::from_utf8(slice) {
82 Ok(s) => match CString::new(s) {
83 Ok(cstr) => cstr.into_raw(),
84 Err(_) => std::ptr::null_mut(),
85 },
86 Err(_) => std::ptr::null_mut(),
87 }
88 }
89 }
90}
91
92#[no_mangle]
94pub extern "C" fn sigil_cstring_free(ptr: *mut c_char) {
95 if !ptr.is_null() {
96 unsafe {
97 drop(CString::from_raw(ptr));
98 }
99 }
100}
101
102#[no_mangle]
105pub extern "C" fn sigil_cstring_len(ptr: *const c_char) -> usize {
106 if ptr.is_null() {
107 return 0;
108 }
109 unsafe { CStr::from_ptr(ptr).to_bytes().len() }
110}
111
112#[no_mangle]
115pub extern "C" fn sigil_cstring_copy(src: *const c_char, dst: *mut u8, dst_len: usize) -> usize {
116 if src.is_null() || dst.is_null() || dst_len == 0 {
117 return 0;
118 }
119
120 unsafe {
121 let c_str = CStr::from_ptr(src);
122 let bytes = c_str.to_bytes();
123 let copy_len = bytes.len().min(dst_len);
124 std::ptr::copy_nonoverlapping(bytes.as_ptr(), dst, copy_len);
125 copy_len
126 }
127}
128
129#[no_mangle]
135pub extern "C" fn sigil_ptr_from_int(addr: i64) -> *mut u8 {
136 addr as *mut u8
137}
138
139#[no_mangle]
141pub extern "C" fn sigil_ptr_to_int(ptr: *const u8) -> i64 {
142 ptr as i64
143}
144
145#[no_mangle]
147pub extern "C" fn sigil_ptr_read_u8(ptr: *const u8) -> u8 {
148 if ptr.is_null() {
149 return 0;
150 }
151 unsafe { *ptr }
152}
153
154#[no_mangle]
156pub extern "C" fn sigil_ptr_write_u8(ptr: *mut u8, value: u8) {
157 if !ptr.is_null() {
158 unsafe {
159 *ptr = value;
160 }
161 }
162}
163
164#[no_mangle]
166pub extern "C" fn sigil_ptr_read_i32(ptr: *const i32) -> i32 {
167 if ptr.is_null() {
168 return 0;
169 }
170 unsafe { *ptr }
171}
172
173#[no_mangle]
175pub extern "C" fn sigil_ptr_write_i32(ptr: *mut i32, value: i32) {
176 if !ptr.is_null() {
177 unsafe {
178 *ptr = value;
179 }
180 }
181}
182
183#[no_mangle]
185pub extern "C" fn sigil_ptr_read_i64(ptr: *const i64) -> i64 {
186 if ptr.is_null() {
187 return 0;
188 }
189 unsafe { *ptr }
190}
191
192#[no_mangle]
194pub extern "C" fn sigil_ptr_write_i64(ptr: *mut i64, value: i64) {
195 if !ptr.is_null() {
196 unsafe {
197 *ptr = value;
198 }
199 }
200}
201
202#[no_mangle]
204pub extern "C" fn sigil_ptr_read_f64(ptr: *const f64) -> f64 {
205 if ptr.is_null() {
206 return 0.0;
207 }
208 unsafe { *ptr }
209}
210
211#[no_mangle]
213pub extern "C" fn sigil_ptr_write_f64(ptr: *mut f64, value: f64) {
214 if !ptr.is_null() {
215 unsafe {
216 *ptr = value;
217 }
218 }
219}
220
221#[no_mangle]
223pub extern "C" fn sigil_ptr_add(ptr: *const u8, offset: i64) -> *const u8 {
224 if ptr.is_null() {
225 return std::ptr::null();
226 }
227 unsafe { ptr.offset(offset as isize) }
228}
229
230#[no_mangle]
232pub extern "C" fn sigil_ptr_is_null(ptr: *const u8) -> i64 {
233 if ptr.is_null() {
234 1
235 } else {
236 0
237 }
238}
239
240#[no_mangle]
247pub extern "C" fn sigil_alloc(size: usize) -> *mut u8 {
248 if size == 0 {
249 return std::ptr::null_mut();
250 }
251
252 let layout = match std::alloc::Layout::from_size_align(size, 8) {
253 Ok(l) => l,
254 Err(_) => return std::ptr::null_mut(),
255 };
256
257 unsafe { std::alloc::alloc_zeroed(layout) }
258}
259
260#[no_mangle]
262pub extern "C" fn sigil_free(ptr: *mut u8, size: usize) {
263 if ptr.is_null() || size == 0 {
264 return;
265 }
266
267 let layout = match std::alloc::Layout::from_size_align(size, 8) {
268 Ok(l) => l,
269 Err(_) => return,
270 };
271
272 unsafe {
273 std::alloc::dealloc(ptr, layout);
274 }
275}
276
277#[no_mangle]
279pub extern "C" fn sigil_realloc(ptr: *mut u8, old_size: usize, new_size: usize) -> *mut u8 {
280 if ptr.is_null() {
281 return sigil_alloc(new_size);
282 }
283
284 if new_size == 0 {
285 sigil_free(ptr, old_size);
286 return std::ptr::null_mut();
287 }
288
289 let old_layout = match std::alloc::Layout::from_size_align(old_size, 8) {
290 Ok(l) => l,
291 Err(_) => return std::ptr::null_mut(),
292 };
293
294 unsafe { std::alloc::realloc(ptr, old_layout, new_size) }
295}
296
297#[no_mangle]
299pub extern "C" fn sigil_memcpy(dst: *mut u8, src: *const u8, size: usize) {
300 if dst.is_null() || src.is_null() || size == 0 {
301 return;
302 }
303 unsafe {
304 std::ptr::copy_nonoverlapping(src, dst, size);
305 }
306}
307
308#[no_mangle]
310pub extern "C" fn sigil_memset(ptr: *mut u8, value: u8, size: usize) {
311 if ptr.is_null() || size == 0 {
312 return;
313 }
314 unsafe {
315 std::ptr::write_bytes(ptr, value, size);
316 }
317}
318
319#[cfg(test)]
320mod tests {
321 use super::*;
322
323 #[test]
324 fn test_string_conversion() {
325 let rust_str = "Hello, World!";
326 let bytes = rust_str.as_bytes();
327
328 let c_str = sigil_string_to_cstring(bytes.as_ptr(), bytes.len());
329 assert!(!c_str.is_null());
330
331 let len = sigil_cstring_len(c_str);
332 assert_eq!(len, rust_str.len());
333
334 sigil_cstring_free(c_str);
335 }
336
337 #[test]
338 fn test_pointer_operations() {
339 let value: i64 = 42;
340 let ptr = &value as *const i64;
341
342 let addr = sigil_ptr_to_int(ptr as *const u8);
343 let recovered_ptr = sigil_ptr_from_int(addr) as *const i64;
344
345 let read_value = sigil_ptr_read_i64(recovered_ptr);
346 assert_eq!(read_value, 42);
347 }
348
349 #[test]
350 fn test_memory_allocation() {
351 let ptr = sigil_alloc(1024);
352 assert!(!ptr.is_null());
353
354 sigil_memset(ptr, 0xAB, 1024);
356
357 unsafe {
359 assert_eq!(*ptr, 0xAB);
360 assert_eq!(*ptr.add(512), 0xAB);
361 }
362
363 sigil_free(ptr, 1024);
364 }
365
366 #[test]
367 fn test_ptr_add() {
368 let array: [u8; 4] = [1, 2, 3, 4];
369 let ptr = array.as_ptr();
370
371 let ptr2 = sigil_ptr_add(ptr, 2);
372 assert_eq!(sigil_ptr_read_u8(ptr2), 3);
373 }
374}