|
1 | 1 | // runtime/native_runtime/src/lib.rs |
2 | 2 | #![allow(clippy::not_unsafe_ptr_arg_deref, clippy::missing_safety_doc)] |
3 | 3 |
|
| 4 | +use std::fmt::Write as FmtWrite; |
4 | 5 | use std::collections::HashMap; |
5 | 6 | use std::ffi::{CStr, CString}; |
6 | 7 | use std::io::{self, Write}; |
@@ -233,85 +234,115 @@ pub unsafe extern "C" fn ts_free_value(val: *mut TsValue) { |
233 | 234 | } |
234 | 235 |
|
235 | 236 | // Convert TsValue to Rust String helper |
236 | | -unsafe fn value_to_string(val: *mut TsValue) -> String { |
| 237 | +unsafe fn value_to_string_impl(val: *mut TsValue, buf: &mut String) { |
237 | 238 | if val.is_null() { |
238 | | - return "null".to_string(); |
| 239 | + let _ = write!(buf, "null"); |
| 240 | + return; |
239 | 241 | } |
240 | 242 | let v = &*val; |
241 | 243 | if v.tag == TsTag::Null as u32 { |
242 | | - "null".to_string() |
| 244 | + let _ = write!(buf, "null"); |
243 | 245 | } else if v.tag == TsTag::Bool as u32 { |
244 | | - v.data.boolean.to_string() |
| 246 | + let _ = write!(buf, "{}", v.data.boolean); |
245 | 247 | } else if v.tag == TsTag::Int as u32 { |
246 | | - v.data.integer.to_string() |
| 248 | + let _ = write!(buf, "{}", v.data.integer); |
247 | 249 | } else if v.tag == TsTag::Float as u32 { |
248 | | - v.data.float.to_string() |
| 250 | + let _ = write!(buf, "{}", v.data.float); |
249 | 251 | } else if v.tag == TsTag::String as u32 { |
250 | 252 | if v.data.pointer.is_null() { |
251 | | - "null".to_string() |
| 253 | + let _ = write!(buf, "null"); |
252 | 254 | } else { |
253 | | - (*(v.data.pointer as *const String)).clone() |
| 255 | + buf.push_str(&*(v.data.pointer as *const String)); |
254 | 256 | } |
255 | 257 | } else if v.tag == TsTag::List as u32 { |
256 | 258 | if v.data.pointer.is_null() { |
257 | | - "[]".to_string() |
| 259 | + let _ = write!(buf, "[]"); |
258 | 260 | } else { |
| 261 | + let _ = write!(buf, "["); |
259 | 262 | let list = &*(v.data.pointer as *const Vec<*mut TsValue>); |
260 | | - let mut parts = Vec::new(); |
261 | | - for &item in list { |
262 | | - parts.push(value_to_string(item)); |
| 263 | + for (i, &item) in list.iter().enumerate() { |
| 264 | + if i > 0 { |
| 265 | + let _ = write!(buf, ", "); |
| 266 | + } |
| 267 | + value_to_string_impl(item, buf); |
263 | 268 | } |
264 | | - format!("[{}]", parts.join(", ")) |
| 269 | + let _ = write!(buf, "]"); |
265 | 270 | } |
266 | 271 | } else if v.tag == TsTag::Map as u32 { |
267 | 272 | if v.data.pointer.is_null() { |
268 | | - "{}".to_string() |
| 273 | + let _ = write!(buf, "{{}}"); |
269 | 274 | } else { |
| 275 | + let _ = write!(buf, "{{"); |
270 | 276 | let map = &*(v.data.pointer as *const HashMap<String, *mut TsValue>); |
271 | | - let mut parts = Vec::new(); |
| 277 | + let mut first = true; |
272 | 278 | for (k, &val) in map { |
273 | | - parts.push(format!("{}: {}", k, value_to_string(val))); |
| 279 | + if !first { |
| 280 | + let _ = write!(buf, ", "); |
| 281 | + } |
| 282 | + first = false; |
| 283 | + let _ = write!(buf, "{}: ", k); |
| 284 | + value_to_string_impl(val, buf); |
274 | 285 | } |
275 | | - format!("{{{}}}", parts.join(", ")) |
| 286 | + let _ = write!(buf, "}}"); |
276 | 287 | } |
277 | 288 | } else if v.tag == TsTag::Struct as u32 { |
278 | 289 | if v.data.pointer.is_null() { |
279 | | - "unknown struct".to_string() |
| 290 | + let _ = write!(buf, "unknown struct"); |
280 | 291 | } else { |
281 | 292 | let s = &*(v.data.pointer as *const TsStruct); |
282 | | - let mut parts = Vec::new(); |
| 293 | + let _ = write!(buf, "{} {{", s.name); |
| 294 | + let mut first = true; |
283 | 295 | for (k, &val) in &s.fields { |
284 | | - parts.push(format!("{}: {}", k, value_to_string(val))); |
| 296 | + if !first { |
| 297 | + let _ = write!(buf, ", "); |
| 298 | + } |
| 299 | + first = false; |
| 300 | + let _ = write!(buf, "{}: ", k); |
| 301 | + value_to_string_impl(val, buf); |
285 | 302 | } |
286 | | - format!("{} {{{}}}", s.name, parts.join(", ")) |
| 303 | + let _ = write!(buf, "}}"); |
287 | 304 | } |
288 | 305 | } else if v.tag == TsTag::Model as u32 { |
289 | 306 | if v.data.pointer.is_null() { |
290 | | - "unknown model".to_string() |
| 307 | + let _ = write!(buf, "unknown model"); |
291 | 308 | } else { |
292 | 309 | let m = &*(v.data.pointer as *const TsModel); |
293 | | - let mut parts = Vec::new(); |
| 310 | + let _ = write!(buf, "{} {{", m.name); |
| 311 | + let mut first = true; |
294 | 312 | for (k, &val) in &m.fields { |
295 | | - parts.push(format!("{}: {}", k, value_to_string(val))); |
| 313 | + if !first { |
| 314 | + let _ = write!(buf, ", "); |
| 315 | + } |
| 316 | + first = false; |
| 317 | + let _ = write!(buf, "{}: ", k); |
| 318 | + value_to_string_impl(val, buf); |
296 | 319 | } |
297 | | - format!("{} {{{}}}", m.name, parts.join(", ")) |
| 320 | + let _ = write!(buf, "}}"); |
298 | 321 | } |
299 | 322 | } else if v.tag == TsTag::Enum as u32 { |
300 | 323 | if v.data.pointer.is_null() { |
301 | | - "unknown enum".to_string() |
| 324 | + let _ = write!(buf, "unknown enum"); |
302 | 325 | } else { |
303 | 326 | let e = &*(v.data.pointer as *const TsEnum); |
304 | 327 | if e.value.is_null() { |
305 | | - format!("{}.{}", e.name, e.variant) |
| 328 | + let _ = write!(buf, "{}.{}", e.name, e.variant); |
306 | 329 | } else { |
307 | | - format!("{}.{}({})", e.name, e.variant, value_to_string(e.value)) |
| 330 | + let _ = write!(buf, "{}.{}(", e.name, e.variant); |
| 331 | + value_to_string_impl(e.value, buf); |
| 332 | + let _ = write!(buf, ")"); |
308 | 333 | } |
309 | 334 | } |
310 | 335 | } else { |
311 | | - "unknown".to_string() |
| 336 | + let _ = write!(buf, "unknown"); |
312 | 337 | } |
313 | 338 | } |
314 | 339 |
|
| 340 | +unsafe fn value_to_string(val: *mut TsValue) -> String { |
| 341 | + let mut s = String::new(); |
| 342 | + value_to_string_impl(val, &mut s); |
| 343 | + s |
| 344 | +} |
| 345 | + |
315 | 346 | // Built-in functions |
316 | 347 | #[no_mangle] |
317 | 348 | pub unsafe extern "C" fn ts_say(val: *mut TsValue) { |
|
0 commit comments