shape_jit/ffi/call_method/
string.rs1use crate::ffi::jit_kinds::*;
16use crate::ffi::value_ffi::*;
17
18#[inline(always)]
20pub fn call_string_method(receiver_bits: u64, method_name: &str, args: &[u64]) -> u64 {
21 unsafe {
22 let s = unbox_string(receiver_bits);
23
24 match method_name {
25 "length" | "len" => box_number(s.len() as f64),
26 "toUpperCase" | "to_upper_case" => box_string(s.to_uppercase()),
27 "toLowerCase" | "to_lower_case" => box_string(s.to_lowercase()),
28 "trim" => box_string(s.trim().to_string()),
29 "split" => {
30 let _ = args;
36 todo!(
37 "phase-2c §2.7.4 / W10 jit-playbook §5: \
38 JitArray rebuild — String.split. Result \
39 allocation needs `TypedArray<Arc<String>>`."
40 )
41 }
42 "includes" | "contains" => {
43 if args.is_empty() {
44 return TAG_BOOL_FALSE;
45 }
46 if is_heap_kind(args[0], HK_STRING) {
47 let needle = unbox_string(args[0]);
48 if s.contains(needle) {
49 return TAG_BOOL_TRUE;
50 }
51 }
52 TAG_BOOL_FALSE
53 }
54 "startsWith" | "starts_with" => {
55 if args.is_empty() {
56 return TAG_BOOL_FALSE;
57 }
58 if is_heap_kind(args[0], HK_STRING) {
59 let prefix = unbox_string(args[0]);
60 if s.starts_with(prefix) {
61 return TAG_BOOL_TRUE;
62 }
63 }
64 TAG_BOOL_FALSE
65 }
66 "endsWith" | "ends_with" => {
67 if args.is_empty() {
68 return TAG_BOOL_FALSE;
69 }
70 if is_heap_kind(args[0], HK_STRING) {
71 let suffix = unbox_string(args[0]);
72 if s.ends_with(suffix) {
73 return TAG_BOOL_TRUE;
74 }
75 }
76 TAG_BOOL_FALSE
77 }
78 "replace" | "replaceAll" | "replace_all" => {
79 if args.len() < 2 {
80 return receiver_bits;
81 }
82 if is_heap_kind(args[0], HK_STRING) && is_heap_kind(args[1], HK_STRING) {
83 let from = unbox_string(args[0]);
84 let to = unbox_string(args[1]);
85 let replaced = s.replace(from, to);
86 return box_string(replaced);
87 }
88 receiver_bits
89 }
90 "charAt" | "char_at" => {
91 if args.is_empty() {
92 return box_string(String::new());
93 }
94 if is_number(args[0]) {
95 let idx = unbox_number(args[0]) as usize;
96 if let Some(ch) = s.chars().nth(idx) {
97 return box_string(ch.to_string());
98 }
99 }
100 box_string(String::new())
101 }
102 "substring" | "slice" => {
103 if args.is_empty() {
104 return receiver_bits;
105 }
106 let start = if is_number(args[0]) {
107 unbox_number(args[0]) as usize
108 } else {
109 0
110 };
111 let end = if args.len() > 1 && is_number(args[1]) {
112 unbox_number(args[1]) as usize
113 } else {
114 s.len()
115 };
116 let len = if end >= start { end - start + 1 } else { 0 };
117 let sub: String = s.chars().skip(start).take(len).collect();
118 box_string(sub)
119 }
120 "concat" => {
121 let mut result = s.to_string();
122 for arg in args.iter() {
123 if is_heap_kind(*arg, HK_STRING) {
124 let arg_s = unbox_string(*arg);
125 result.push_str(arg_s);
126 } else if is_number(*arg) {
127 result.push_str(&format!("{}", unbox_number(*arg)));
128 }
129 }
130 box_string(result)
131 }
132 "indexOf" | "index_of" => {
133 if args.is_empty() {
134 return box_number(-1.0);
135 }
136 if is_heap_kind(args[0], HK_STRING) {
137 let needle = unbox_string(args[0]);
138 if let Some(idx) = s.find(needle) {
139 return box_number(idx as f64);
140 }
141 }
142 box_number(-1.0)
143 }
144 "lastIndexOf" | "last_index_of" => {
145 if args.is_empty() {
146 return box_number(-1.0);
147 }
148 if is_heap_kind(args[0], HK_STRING) {
149 let needle = unbox_string(args[0]);
150 if let Some(idx) = s.rfind(needle) {
151 return box_number(idx as f64);
152 }
153 }
154 box_number(-1.0)
155 }
156 "trimStart" | "trim_start" => box_string(s.trim_start().to_string()),
157 "trimEnd" | "trim_end" => box_string(s.trim_end().to_string()),
158 "toNumber" | "to_number" => match s.trim().parse::<f64>() {
159 Ok(n) => box_number(n),
160 Err(_) => TAG_NULL,
161 },
162 "toBool" | "to_bool" => match s.trim() {
163 "true" => TAG_BOOL_TRUE,
164 "false" => TAG_BOOL_FALSE,
165 _ => TAG_NULL,
166 },
167 "chars" => {
168 todo!(
174 "phase-2c §2.7.4 / W10 jit-playbook §5: \
175 JitArray rebuild — String.chars. Result \
176 allocation needs `TypedArray<Arc<String>>`."
177 )
178 }
179 "isEmpty" | "is_empty" => {
180 if s.is_empty() {
181 TAG_BOOL_TRUE
182 } else {
183 TAG_BOOL_FALSE
184 }
185 }
186 "repeat" => {
187 if args.is_empty() {
188 return receiver_bits;
189 }
190 if is_number(args[0]) {
191 let count = unbox_number(args[0]) as usize;
192 let repeated = s.repeat(count);
193 return box_string(repeated);
194 }
195 receiver_bits
196 }
197 "padStart" | "pad_start" => {
198 if args.is_empty() {
199 return receiver_bits;
200 }
201 let target_len = if is_number(args[0]) {
202 unbox_number(args[0]) as usize
203 } else {
204 return receiver_bits;
205 };
206 let pad_char = if args.len() > 1 && is_heap_kind(args[1], HK_STRING) {
207 let pad_s = unbox_string(args[1]);
208 pad_s.chars().next().unwrap_or(' ')
209 } else {
210 ' '
211 };
212 if s.len() >= target_len {
213 return receiver_bits;
214 }
215 let padding: String = std::iter::repeat_n(pad_char, target_len - s.len()).collect();
216 let padded = format!("{}{}", padding, s);
217 box_string(padded)
218 }
219 "padEnd" | "pad_end" => {
220 if args.is_empty() {
221 return receiver_bits;
222 }
223 let target_len = if is_number(args[0]) {
224 unbox_number(args[0]) as usize
225 } else {
226 return receiver_bits;
227 };
228 let pad_char = if args.len() > 1 && is_heap_kind(args[1], HK_STRING) {
229 let pad_s = unbox_string(args[1]);
230 pad_s.chars().next().unwrap_or(' ')
231 } else {
232 ' '
233 };
234 if s.len() >= target_len {
235 return receiver_bits;
236 }
237 let padding: String = std::iter::repeat_n(pad_char, target_len - s.len()).collect();
238 let padded = format!("{}{}", s, padding);
239 box_string(padded)
240 }
241 _ => TAG_NULL,
242 }
243 }
244}