Skip to main content

seq_runtime/string_ops/
basic.rs

1//! Basic string operations: length, byte-length, empty-check, equality, concat.
2
3use crate::seqstring::global_string;
4use crate::stack::{Stack, pop, push};
5use crate::value::Value;
6
7/// # Safety
8/// Stack must have the expected values on top for this operation.
9#[unsafe(no_mangle)]
10pub unsafe extern "C" fn patch_seq_string_empty(stack: Stack) -> Stack {
11    assert!(!stack.is_null(), "string_empty: stack is empty");
12
13    let (stack, value) = unsafe { pop(stack) };
14
15    match value {
16        Value::String(s) => {
17            let is_empty = s.as_str().is_empty();
18            unsafe { push(stack, Value::Bool(is_empty)) }
19        }
20        _ => panic!("string_empty: expected String on stack"),
21    }
22}
23
24/// Check if a string contains a substring
25///
26/// Stack effect: ( str substring -- bool )
27///
28/// # Safety
29/// Stack must have two String values on top
30#[unsafe(no_mangle)]
31pub unsafe extern "C" fn patch_seq_string_concat(stack: Stack) -> Stack {
32    assert!(!stack.is_null(), "string_concat: stack is empty");
33
34    let (stack, str2_val) = unsafe { pop(stack) };
35    assert!(!stack.is_null(), "string_concat: need two strings");
36    let (stack, str1_val) = unsafe { pop(stack) };
37
38    match (str1_val, str2_val) {
39        (Value::String(s1), Value::String(s2)) => {
40            let result = format!("{}{}", s1.as_str(), s2.as_str());
41            unsafe { push(stack, Value::String(global_string(result))) }
42        }
43        _ => panic!("string_concat: expected two strings on stack"),
44    }
45}
46
47/// Get the length of a string in Unicode characters (code points)
48///
49/// Stack effect: ( str -- int )
50///
51/// Note: This returns character count, not byte count.
52/// For UTF-8 byte length (e.g., HTTP Content-Length), use `string-byte-length`.
53///
54/// # Safety
55/// Stack must have a String value on top
56#[unsafe(no_mangle)]
57pub unsafe extern "C" fn patch_seq_string_length(stack: Stack) -> Stack {
58    assert!(!stack.is_null(), "string_length: stack is empty");
59
60    let (stack, str_val) = unsafe { pop(stack) };
61
62    match str_val {
63        Value::String(s) => {
64            let len = s.as_str().chars().count() as i64;
65            unsafe { push(stack, Value::Int(len)) }
66        }
67        _ => panic!("string_length: expected String on stack"),
68    }
69}
70
71/// Get the byte length of a string (UTF-8 encoded)
72///
73/// Stack effect: ( str -- int )
74///
75/// Use this for HTTP Content-Length headers and buffer allocation.
76///
77/// # Safety
78/// Stack must have a String value on top
79#[unsafe(no_mangle)]
80pub unsafe extern "C" fn patch_seq_string_byte_length(stack: Stack) -> Stack {
81    assert!(!stack.is_null(), "string_byte_length: stack is empty");
82
83    let (stack, str_val) = unsafe { pop(stack) };
84
85    match str_val {
86        Value::String(s) => {
87            let len = s.as_str().len() as i64;
88            unsafe { push(stack, Value::Int(len)) }
89        }
90        _ => panic!("string_byte_length: expected String on stack"),
91    }
92}
93
94/// Get the Unicode code point at a character index
95///
96/// Stack effect: ( str int -- int )
97///
98/// Returns the code point value at the given character index.
99/// Returns -1 if index is out of bounds.
100///
101/// # Safety
102/// Stack must have a String and Int on top
103#[unsafe(no_mangle)]
104pub unsafe extern "C" fn patch_seq_string_equal(stack: Stack) -> Stack {
105    assert!(!stack.is_null(), "string_equal: stack is empty");
106
107    let (stack, str2_val) = unsafe { pop(stack) };
108    assert!(!stack.is_null(), "string_equal: need two strings");
109    let (stack, str1_val) = unsafe { pop(stack) };
110
111    match (str1_val, str2_val) {
112        (Value::String(s1), Value::String(s2)) => {
113            let equal = s1.as_str() == s2.as_str();
114            unsafe { push(stack, Value::Bool(equal)) }
115        }
116        _ => panic!("string_equal: expected two strings on stack"),
117    }
118}