1use crate::seqstring::global_string;
4use crate::stack::{Stack, pop, push};
5use crate::value::Value;
6use std::sync::Arc;
7
8#[unsafe(no_mangle)]
11pub unsafe extern "C" fn patch_seq_string_split(stack: Stack) -> Stack {
12 use crate::value::VariantData;
13
14 assert!(!stack.is_null(), "string_split: stack is empty");
15
16 let (stack, delim_val) = unsafe { pop(stack) };
17 assert!(!stack.is_null(), "string_split: need two strings");
18 let (stack, str_val) = unsafe { pop(stack) };
19
20 match (str_val, delim_val) {
21 (Value::String(s), Value::String(d)) => {
22 let fields: Vec<Value> = s
24 .as_str()
25 .split(d.as_str())
26 .map(|part| Value::String(global_string(part.to_owned())))
27 .collect();
28
29 let variant = Value::Variant(Arc::new(VariantData::new(
31 global_string("List".to_string()),
32 fields,
33 )));
34
35 unsafe { push(stack, variant) }
36 }
37 _ => panic!("string_split: expected two strings on stack"),
38 }
39}
40
41#[unsafe(no_mangle)]
48pub unsafe extern "C" fn patch_seq_string_contains(stack: Stack) -> Stack {
49 assert!(!stack.is_null(), "string_contains: stack is empty");
50
51 let (stack, substring_val) = unsafe { pop(stack) };
52 assert!(!stack.is_null(), "string_contains: need two strings");
53 let (stack, str_val) = unsafe { pop(stack) };
54
55 match (str_val, substring_val) {
56 (Value::String(s), Value::String(sub)) => {
57 let contains = s.as_str().contains(sub.as_str());
58 unsafe { push(stack, Value::Bool(contains)) }
59 }
60 _ => panic!("string_contains: expected two strings on stack"),
61 }
62}
63
64#[unsafe(no_mangle)]
71pub unsafe extern "C" fn patch_seq_string_starts_with(stack: Stack) -> Stack {
72 assert!(!stack.is_null(), "string_starts_with: stack is empty");
73
74 let (stack, prefix_val) = unsafe { pop(stack) };
75 assert!(!stack.is_null(), "string_starts_with: need two strings");
76 let (stack, str_val) = unsafe { pop(stack) };
77
78 match (str_val, prefix_val) {
79 (Value::String(s), Value::String(prefix)) => {
80 let starts = s.as_str().starts_with(prefix.as_str());
81 unsafe { push(stack, Value::Bool(starts)) }
82 }
83 _ => panic!("string_starts_with: expected two strings on stack"),
84 }
85}
86
87#[unsafe(no_mangle)]
94pub unsafe extern "C" fn patch_seq_string_char_at(stack: Stack) -> Stack {
95 assert!(!stack.is_null(), "string_char_at: stack is empty");
96
97 let (stack, index_val) = unsafe { pop(stack) };
98 assert!(!stack.is_null(), "string_char_at: need string and index");
99 let (stack, str_val) = unsafe { pop(stack) };
100
101 match (str_val, index_val) {
102 (Value::String(s), Value::Int(index)) => {
103 let result = if index < 0 {
104 -1
105 } else {
106 s.as_str()
107 .chars()
108 .nth(index as usize)
109 .map(|c| c as i64)
110 .unwrap_or(-1)
111 };
112 unsafe { push(stack, Value::Int(result)) }
113 }
114 _ => panic!("string_char_at: expected String and Int on stack"),
115 }
116}
117
118#[unsafe(no_mangle)]
134pub unsafe extern "C" fn patch_seq_string_substring(stack: Stack) -> Stack {
135 assert!(!stack.is_null(), "string_substring: stack is empty");
136
137 let (stack, len_val) = unsafe { pop(stack) };
138 assert!(
139 !stack.is_null(),
140 "string_substring: need string, start, len"
141 );
142 let (stack, start_val) = unsafe { pop(stack) };
143 assert!(
144 !stack.is_null(),
145 "string_substring: need string, start, len"
146 );
147 let (stack, str_val) = unsafe { pop(stack) };
148
149 match (str_val, start_val, len_val) {
150 (Value::String(s), Value::Int(start), Value::Int(len)) => {
151 let result = if start < 0 || len < 0 {
152 String::new()
153 } else {
154 s.as_str()
155 .chars()
156 .skip(start as usize)
157 .take(len as usize)
158 .collect()
159 };
160 unsafe { push(stack, Value::String(global_string(result))) }
161 }
162 _ => panic!("string_substring: expected String, Int, Int on stack"),
163 }
164}
165
166#[unsafe(no_mangle)]
176pub unsafe extern "C" fn patch_seq_char_to_string(stack: Stack) -> Stack {
177 assert!(!stack.is_null(), "char_to_string: stack is empty");
178
179 let (stack, code_point_val) = unsafe { pop(stack) };
180
181 match code_point_val {
182 Value::Int(code_point) => {
183 let result = if !(0..=0x10FFFF).contains(&code_point) {
184 String::new()
186 } else {
187 match char::from_u32(code_point as u32) {
188 Some(c) => c.to_string(),
189 None => String::new(), }
191 };
192 unsafe { push(stack, Value::String(global_string(result))) }
193 }
194 _ => panic!("char_to_string: expected Int on stack"),
195 }
196}
197
198#[unsafe(no_mangle)]
208pub unsafe extern "C" fn patch_seq_string_find(stack: Stack) -> Stack {
209 assert!(!stack.is_null(), "string_find: stack is empty");
210
211 let (stack, needle_val) = unsafe { pop(stack) };
212 assert!(!stack.is_null(), "string_find: need string and needle");
213 let (stack, str_val) = unsafe { pop(stack) };
214
215 match (str_val, needle_val) {
216 (Value::String(haystack), Value::String(needle)) => {
217 let haystack_str = haystack.as_str();
218 let needle_str = needle.as_str();
219
220 let result = match haystack_str.find(needle_str) {
222 Some(byte_pos) => {
223 haystack_str[..byte_pos].chars().count() as i64
225 }
226 None => -1,
227 };
228 unsafe { push(stack, Value::Int(result)) }
229 }
230 _ => panic!("string_find: expected two Strings on stack"),
231 }
232}
233
234#[unsafe(no_mangle)]
241pub unsafe extern "C" fn patch_seq_string_join(stack: Stack) -> Stack {
242 unsafe {
243 let (stack, sep_val) = pop(stack);
245 let sep = match &sep_val {
246 Value::String(s) => s.as_str().to_owned(),
247 _ => panic!("string.join: expected String separator, got {:?}", sep_val),
248 };
249
250 let (stack, list_val) = pop(stack);
252 let variant_data = match &list_val {
253 Value::Variant(v) => v,
254 _ => panic!("string.join: expected Variant (list), got {:?}", list_val),
255 };
256
257 let parts: Vec<String> = variant_data
259 .fields
260 .iter()
261 .map(|v| match v {
262 Value::String(s) => s.as_str().to_owned(),
263 Value::Int(n) => n.to_string(),
264 Value::Float(f) => f.to_string(),
265 Value::Bool(b) => if *b { "true" } else { "false" }.to_string(),
266 Value::Symbol(s) => format!(":{}", s.as_str()),
267 _ => format!("{:?}", v),
268 })
269 .collect();
270
271 let result = parts.join(&sep);
272 push(stack, Value::String(global_string(result)))
273 }
274}