Skip to main content

palladium/runtime/
string_ops.rs

1// Runtime string operations for Palladium
2// These will be available as built-in functions
3
4#![allow(clippy::not_unsafe_ptr_arg_deref)]
5
6use std::ffi::{CStr, CString};
7use std::os::raw::c_char;
8
9#[repr(C)]
10pub struct PdString {
11    data: *mut c_char,
12    len: i64,
13    capacity: i64,
14}
15
16/// String concatenation
17///
18/// # Safety
19/// The caller must ensure that:
20/// - Both `a` and `b` are valid pointers to PdString structs
21/// - The data field in both structs points to valid null-terminated C strings
22/// - The lifetime of the input strings extends through this function call
23#[no_mangle]
24pub unsafe extern "C" fn pd_string_concat(a: *const PdString, b: *const PdString) -> PdString {
25    unsafe {
26        let a_str = CStr::from_ptr((*a).data).to_string_lossy();
27        let b_str = CStr::from_ptr((*b).data).to_string_lossy();
28        let result = format!("{}{}", a_str, b_str);
29
30        let c_string = CString::new(result).unwrap();
31        let len = c_string.as_bytes().len() as i64;
32        let data = c_string.into_raw();
33
34        PdString {
35            data,
36            len,
37            capacity: len,
38        }
39    }
40}
41
42/// String append (modifies first string)
43///
44/// # Safety
45/// The caller must ensure that:
46/// - `a` is a valid mutable pointer to a PdString struct
47/// - `b` is a valid pointer to a PdString struct
48/// - The data fields in both structs point to valid null-terminated C strings
49/// - The caller is responsible for the memory management of the PdString at `a`
50#[no_mangle]
51pub unsafe extern "C" fn pd_string_append(a: *mut PdString, b: *const PdString) {
52    unsafe {
53        let a_str = CStr::from_ptr((*a).data).to_string_lossy().into_owned();
54        let b_str = CStr::from_ptr((*b).data).to_string_lossy();
55        let result = format!("{}{}", a_str, b_str);
56
57        // Free old data
58        let _ = CString::from_raw((*a).data);
59
60        let c_string = CString::new(result).unwrap();
61        let len = c_string.as_bytes().len() as i64;
62        let data = c_string.into_raw();
63
64        (*a).data = data;
65        (*a).len = len;
66        (*a).capacity = len;
67    }
68}
69
70// Create string from integer
71#[no_mangle]
72pub extern "C" fn pd_int_to_string(n: i64) -> PdString {
73    let s = n.to_string();
74    let c_string = CString::new(s).unwrap();
75    let len = c_string.as_bytes().len() as i64;
76    let data = c_string.into_raw();
77
78    PdString {
79        data,
80        len,
81        capacity: len,
82    }
83}
84
85/// String length (already exists but let's make it consistent)
86///
87/// # Safety
88/// The caller must ensure that:
89/// - `s` is a valid pointer to a PdString struct
90/// - The PdString has been properly initialized
91#[no_mangle]
92pub unsafe extern "C" fn pd_string_length(s: *const PdString) -> i64 {
93    unsafe { (*s).len }
94}