roan_engine/value/methods/
string.rs

1use 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}