roan_engine/value/methods/
string.rs1use crate::{
2 as_cast, native_function,
3 value::Value,
4 vm::native_fn::{NativeFunction, NativeFunctionParam},
5};
6
7native_function!(
8 fn __string_len(s) {
9 let string = as_cast!(s, String);
10
11 Value::Int(string.len() as i64)
12 }
13);
14
15native_function!(
16 fn __string_split(s, sep) {
17 let s = as_cast!(s, String);
18 let sep = as_cast!(sep, String);
19
20 Value::Vec(
21 s.split(&sep)
22 .map(|s| Value::String(s.to_string()))
23 .collect(),
24 )
25 }
26);
27
28native_function!(
29 fn __string_chars(s) {
30 let s = as_cast!(s, String);
31
32 Value::Vec(
33 s.chars().map(|c| Value::Char(c)).collect(),
34 )
35 }
36);
37
38native_function!(
39 fn __string_contains(s, needle) {
40 let s = as_cast!(s, String);
41 let needle = as_cast!(needle, String);
42
43 Value::Bool(s.contains(&needle))
44 }
45);
46
47native_function!(
48 fn __string_starts_with(s, needle) {
49 let s = as_cast!(s, String);
50 let needle = as_cast!(needle, String);
51
52 Value::Bool(s.starts_with(&needle))
53 }
54);
55
56native_function!(
57 fn __string_ends_with(s, needle) {
58 let s = as_cast!(s, String);
59 let needle = as_cast!(needle, String);
60
61 Value::Bool(s.ends_with(&needle))
62 }
63);
64
65native_function!(
66 fn __string_replace(s, needle, replacement) {
67 let s = as_cast!(s, String);
68 let needle = as_cast!(needle, String);
69 let replacement = as_cast!(replacement, String);
70
71 Value::String(s.replace(&needle, &replacement))
72 }
73);
74
75native_function!(
76 fn __string_trim(s) {
77 let s = as_cast!(s, String);
78
79 Value::String(s.trim().to_string())
80 }
81);
82
83native_function!(
84 fn __string_trim_start(s) {
85 let s = as_cast!(s, String);
86
87 Value::String(s.trim_start().to_string())
88 }
89);
90
91native_function!(
92 fn __string_trim_end(s) {
93 let s = as_cast!(s, String);
94
95 Value::String(s.trim_end().to_string())
96 }
97);
98
99native_function!(
100 fn __string_to_uppercase(s) {
101 let s = as_cast!(s, String);
102
103 Value::String(s.to_uppercase())
104 }
105);
106
107native_function!(
108 fn __string_to_lowercase(s) {
109 let s = as_cast!(s, String);
110
111 Value::String(s.to_lowercase())
112 }
113);
114
115native_function!(
116 fn __string_reverse(s) {
117 let s = as_cast!(s, String);
118
119 Value::String(s.chars().rev().collect())
120 }
121);
122
123native_function!(
124 fn __string_char_at(s, index) {
125 let s = as_cast!(s, String);
126 let index = as_cast!(index, Int);
127
128 let index = if index < 0 {
129 s.len() as i64 + index
130 } else {
131 index
132 };
133
134 if index < 0 || index as usize >= s.len() {
135 return Value::Null;
136 }
137
138 Value::String(s.chars().nth(index as usize).unwrap().to_string())
139 }
140);
141
142native_function!(
143 fn __string_char_code_at(s, index) {
144 let s = as_cast!(s, String);
145 let index = as_cast!(index, Int);
146
147 let index = if index < 0 {
148 s.len() as i64 + index
149 } else {
150 index
151 };
152
153 if index < 0 || index as usize >= s.len() {
154 return Value::Null;
155 }
156
157 Value::Int(s.chars().nth(index as usize).unwrap() as i64)
158 }
159);
160
161native_function!(
162 fn __string_slice(s, start, end) {
163 let s = as_cast!(s, String);
164 let start = as_cast!(start, Int);
165 let end = as_cast!(end, Int);
166
167 let start = if start < 0 {
168 s.len() as i64 + start
169 } else {
170 start
171 };
172
173 let end = if end < 0 {
174 s.len() as i64 + end
175 } else {
176 end
177 };
178
179 if start < 0 || end < 0 || start as usize >= s.len() || end as usize >= s.len() {
180 return Value::Null;
181 }
182
183 Value::String(s.chars().skip(start as usize).take((end - start) as usize).collect())
184 }
185);
186
187native_function!(
188 fn __string_index_of(s, needle) {
189 let s = as_cast!(s, String);
190 let needle = as_cast!(needle, String);
191
192 Value::Int(s.find(&needle).map(|i| i as i64).unwrap_or(-1))
193 }
194);
195
196native_function!(
197 fn __string_last_index_of(s, needle) {
198 let s = as_cast!(s, String);
199 let needle = as_cast!(needle, String);
200
201 Value::Int(s.rfind(&needle).map(|i| i as i64).unwrap_or(-1))
202 }
203);
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208 use crate::value::Value;
209
210 #[test]
211 fn test_string_len() {
212 let result = __string_len()
213 .call(vec![Value::String("Hello".to_string())])
214 .unwrap();
215
216 assert_eq!(result, Value::Int(5));
217 }
218
219 #[test]
220 fn test_string_split() {
221 let result = __string_split()
222 .call(vec![
223 Value::String("Hello,World".to_string()),
224 Value::String(",".to_string()),
225 ])
226 .unwrap();
227
228 assert_eq!(
229 result,
230 Value::Vec(vec![
231 Value::String("Hello".to_string()),
232 Value::String("World".to_string())
233 ])
234 );
235 }
236
237 #[test]
238 fn test_string_chars() {
239 let result = __string_chars()
240 .call(vec![Value::String("Hello".to_string())])
241 .unwrap();
242
243 assert_eq!(
244 result,
245 Value::Vec(vec![
246 Value::Char('H'),
247 Value::Char('e'),
248 Value::Char('l'),
249 Value::Char('l'),
250 Value::Char('o')
251 ])
252 );
253 }
254
255 #[test]
256 fn test_string_contains() {
257 let result = __string_contains()
258 .call(vec![
259 Value::String("Hello".to_string()),
260 Value::String("ell".to_string()),
261 ])
262 .unwrap();
263
264 assert_eq!(result, Value::Bool(true));
265 }
266
267 #[test]
268 fn test_string_starts_with() {
269 let result = __string_starts_with()
270 .call(vec![
271 Value::String("Hello".to_string()),
272 Value::String("Hel".to_string()),
273 ])
274 .unwrap();
275
276 assert_eq!(result, Value::Bool(true));
277 }
278
279 #[test]
280 fn test_string_ends_with() {
281 let result = __string_ends_with()
282 .call(vec![
283 Value::String("Hello".to_string()),
284 Value::String("lo".to_string()),
285 ])
286 .unwrap();
287
288 assert_eq!(result, Value::Bool(true));
289 }
290
291 #[test]
292 fn test_string_replace() {
293 let result = __string_replace()
294 .call(vec![
295 Value::String("Hello,World".to_string()),
296 Value::String(",".to_string()),
297 Value::String(" ".to_string()),
298 ])
299 .unwrap();
300
301 assert_eq!(result, Value::String("Hello World".to_string()));
302 }
303
304 #[test]
305 fn test_string_trim() {
306 let result = __string_trim()
307 .call(vec![Value::String(" Hello ".to_string())])
308 .unwrap();
309
310 assert_eq!(result, Value::String("Hello".to_string()));
311 }
312
313 #[test]
314 fn test_string_trim_start() {
315 let result = __string_trim_start()
316 .call(vec![Value::String(" Hello".to_string())])
317 .unwrap();
318
319 assert_eq!(result, Value::String("Hello".to_string()));
320 }
321
322 #[test]
323 fn test_string_trim_end() {
324 let result = __string_trim_end()
325 .call(vec![Value::String("Hello ".to_string())])
326 .unwrap();
327
328 assert_eq!(result, Value::String("Hello".to_string()));
329 }
330
331 #[test]
332 fn test_string_to_uppercase() {
333 let result = __string_to_uppercase()
334 .call(vec![Value::String("Hello".to_string())])
335 .unwrap();
336
337 assert_eq!(result, Value::String("HELLO".to_string()));
338 }
339
340 #[test]
341 fn test_string_to_lowercase() {
342 let result = __string_to_lowercase()
343 .call(vec![Value::String("Hello".to_string())])
344 .unwrap();
345
346 assert_eq!(result, Value::String("hello".to_string()));
347 }
348
349 #[test]
350 fn test_string_reverse() {
351 let result = __string_reverse()
352 .call(vec![Value::String("Hello".to_string())])
353 .unwrap();
354
355 assert_eq!(result, Value::String("olleH".to_string()));
356 }
357
358 #[test]
359 fn test_string_char_at() {
360 let result = __string_char_at()
361 .call(vec![Value::String("Hello".to_string()), Value::Int(1)])
362 .unwrap();
363
364 assert_eq!(result, Value::String("e".to_string()));
365 }
366
367 #[test]
368 fn test_string_char_code_at() {
369 let result = __string_char_code_at()
370 .call(vec![Value::String("Hello".to_string()), Value::Int(1)])
371 .unwrap();
372
373 assert_eq!(result, Value::Int(101));
374 }
375
376 #[test]
377 fn test_string_slice() {
378 let result = __string_slice()
379 .call(vec![
380 Value::String("Hello".to_string()),
381 Value::Int(1),
382 Value::Int(3),
383 ])
384 .unwrap();
385
386 assert_eq!(result, Value::String("el".to_string()));
387 }
388
389 #[test]
390 fn test_string_index_of() {
391 let result = __string_index_of()
392 .call(vec![
393 Value::String("Hello".to_string()),
394 Value::String("l".to_string()),
395 ])
396 .unwrap();
397
398 assert_eq!(result, Value::Int(2));
399 }
400
401 #[test]
402 fn test_string_last_index_of() {
403 let result = __string_last_index_of()
404 .call(vec![
405 Value::String("Hello".to_string()),
406 Value::String("l".to_string()),
407 ])
408 .unwrap();
409
410 assert_eq!(result, Value::Int(3));
411 }
412}