pipeline_script/core/
builtin.rs

1use std::collections::HashMap;
2use std::ffi::{c_char, c_void, CStr, CString};
3use std::io;
4use std::process::{Command, Stdio};
5use std::sync::Mutex;
6use std::thread::{self, JoinHandle};
7use std::time::{Duration, SystemTime, UNIX_EPOCH};
8
9use lazy_static::lazy_static;
10
11#[repr(C)]
12#[derive(Clone, Copy)]
13pub struct Array {
14    len: i64,
15    ptr: *mut Any,
16}
17#[repr(C)]
18#[derive(Clone, Copy)]
19pub struct Any {
20    id: i32,
21    ptr: *mut i8,
22}
23#[allow(unused)]
24pub extern "C" fn len(target: Array) -> i64 {
25    target.len
26}
27
28/// 创建一个新的HashMap<String,String>并返回其指针
29///
30/// # 返回值
31/// 返回指向新创建的HashMap的指针,需要调用方负责内存管理
32///
33/// # 说明
34/// 该函数会在堆上分配一个新的HashMap<String,String>
35/// 调用方需要使用相应的释放函数来避免内存泄漏
36pub extern "C" fn hashmap() -> *mut c_void {
37    let map = Box::new(HashMap::<String, String>::new());
38    Box::into_raw(map) as *mut c_void
39}
40
41/// 向HashMap中插入键值对
42///
43/// # 参数
44/// * `map_ptr` - HashMap的指针
45/// * `key` - 键的C字符串指针
46/// * `value` - 值的C字符串指针
47///
48/// # 说明
49/// 如果键已存在,会更新对应的值
50pub(crate) extern "C" fn hashmap_insert(
51    map_ptr: *mut c_void,
52    key: *const c_char,
53    value: *const c_char,
54) {
55    if map_ptr.is_null() || key.is_null() || value.is_null() {
56        return;
57    }
58
59    let map = unsafe { &mut *(map_ptr as *mut HashMap<String, String>) };
60    let key_str = unsafe { CStr::from_ptr(key).to_str().unwrap_or("").to_string() };
61    let value_str = unsafe { CStr::from_ptr(value).to_str().unwrap_or("").to_string() };
62
63    map.insert(key_str, value_str);
64}
65
66/// 从HashMap中获取指定键的值
67///
68/// # 参数
69/// * `map_ptr` - HashMap的指针
70/// * `key` - 键的C字符串指针
71///
72/// # 返回值
73/// 返回对应值的C字符串指针,如果键不存在返回null指针
74///
75/// # 说明
76/// 返回的字符串需要调用方释放内存
77pub(crate) extern "C" fn hashmap_get(map_ptr: *mut c_void, key: *const c_char) -> *mut c_char {
78    if map_ptr.is_null() || key.is_null() {
79        return std::ptr::null_mut();
80    }
81
82    let map = unsafe { &*(map_ptr as *const HashMap<String, String>) };
83    let key_str = unsafe { CStr::from_ptr(key).to_str().unwrap_or("") };
84
85    match map.get(key_str) {
86        Some(value) => match CString::new(value.clone()) {
87            Ok(c_string) => c_string.into_raw(),
88            Err(_) => std::ptr::null_mut(),
89        },
90        None => std::ptr::null_mut(),
91    }
92}
93
94/// 从HashMap中移除指定键的键值对
95///
96/// # 参数
97/// * `map_ptr` - HashMap的指针
98/// * `key` - 要移除的键的C字符串指针
99///
100/// # 返回值
101/// 如果键存在并被移除返回true,否则返回false
102pub(crate) extern "C" fn hashmap_remove(map_ptr: *mut c_void, key: *const c_char) -> bool {
103    if map_ptr.is_null() || key.is_null() {
104        return false;
105    }
106
107    let map = unsafe { &mut *(map_ptr as *mut HashMap<String, String>) };
108    let key_str = unsafe { CStr::from_ptr(key).to_str().unwrap_or("") };
109
110    map.remove(key_str).is_some()
111}
112
113/// 检查HashMap中是否包含指定的键
114///
115/// # 参数
116/// * `map_ptr` - HashMap的指针
117/// * `key` - 要检查的键的C字符串指针
118///
119/// # 返回值
120/// 如果键存在返回true,否则返回false
121pub(crate) extern "C" fn hashmap_contains_key(map_ptr: *mut c_void, key: *const c_char) -> bool {
122    if map_ptr.is_null() || key.is_null() {
123        return false;
124    }
125
126    let map = unsafe { &*(map_ptr as *const HashMap<String, String>) };
127    let key_str = unsafe { CStr::from_ptr(key).to_str().unwrap_or("") };
128
129    map.contains_key(key_str)
130}
131
132/// 获取HashMap中键值对的数量
133///
134/// # 参数
135/// * `map_ptr` - HashMap的指针
136///
137/// # 返回值
138/// 返回HashMap中键值对的数量,如果指针无效返回0
139pub extern "C" fn hashmap_len(map_ptr: *mut c_void) -> i64 {
140    if map_ptr.is_null() {
141        return 0;
142    }
143
144    let map = unsafe { &*(map_ptr as *const HashMap<String, String>) };
145    map.len() as i64
146}
147
148/// 清空HashMap中的所有键值对
149///
150/// # 参数
151/// * `map_ptr` - HashMap的指针
152pub extern "C" fn hashmap_clear(map_ptr: *mut c_void) {
153    if map_ptr.is_null() {
154        return;
155    }
156
157    let map = unsafe { &mut *(map_ptr as *mut HashMap<String, String>) };
158    map.clear();
159}
160
161/// 释放HashMap的内存
162///
163/// # 参数
164/// * `map_ptr` - 要释放的HashMap指针
165///
166/// # 说明
167/// 调用此函数后,指针将变为无效,不应再使用
168pub extern "C" fn hashmap_free(map_ptr: *mut c_void) {
169    if map_ptr.is_null() {
170        return;
171    }
172
173    unsafe {
174        let _map = Box::from_raw(map_ptr as *mut HashMap<String, String>);
175        // Box会在这里自动释放内存
176    }
177}
178pub(crate) extern "C" fn println(l: i64, ptr: *mut Any) {
179    for i in 0..l {
180        let obj = unsafe { (ptr).offset(i as isize) };
181        unsafe {
182            match (*obj).id {
183                0 => {
184                    print!("Unit")
185                }
186                1 => {
187                    let b = (*obj).ptr as *mut bool;
188                    print!("{}", *b);
189                }
190                3 => {
191                    let value = (*obj).ptr as i8;
192                    print!("{}", value);
193                }
194                5 => {
195                    let value = (*obj).ptr as i16;
196                    print!("{}", value);
197                }
198                7 => {
199                    let v = (*obj).ptr as i32;
200                    print!("{}", v);
201                }
202                9 => {
203                    let v = (*obj).ptr as i64;
204                    print!("{}", v);
205                }
206                11 => {
207                    let v = (*obj).ptr as *mut f32;
208                    print!("{}", *v);
209                }
210                13 => {
211                    let v = (*obj).ptr as *mut f64;
212                    print!("{}", *v);
213                }
214                15 => {
215                    let s = CStr::from_ptr((*obj).ptr as *const c_char);
216                    match s.to_str() {
217                        Ok(s) => print!("{}", s),
218                        Err(_) => print!("InvalidUTF8String"),
219                    }
220                }
221                17 => {
222                    print!("Any")
223                }
224                _ => {
225                    // 对于未知类型,输出类型ID和地址以便调试
226                    print!("Unknown(id:{}, ptr:{:p})", (*obj).id, (*obj).ptr);
227                }
228            }
229            if i < l - 1 {
230                print!("\t")
231            }
232        }
233    }
234    println!()
235}
236#[allow(unused)]
237pub extern "C" fn print(obj: Array) {
238    for i in 0..obj.len {
239        let obj = unsafe { (obj.ptr).offset(i as isize) };
240        unsafe {
241            match (*obj).id {
242                0 => {
243                    print!("Unit")
244                }
245                1 => {
246                    let b = (*obj).ptr as *mut bool;
247                    print!("{}", *b);
248                }
249                3 => {
250                    let value = (*obj).ptr as i8;
251                    print!("{}", value);
252                }
253                5 => {
254                    let value = (*obj).ptr as i16;
255                    print!("{}", value);
256                }
257                7 => {
258                    let v = (*obj).ptr as i32;
259                    print!("{}", v);
260                }
261                9 => {
262                    let v = (*obj).ptr as i64;
263                    print!("{}", v);
264                }
265                11 => {
266                    let v = (*obj).ptr as *mut f32;
267                    print!("{}", *v);
268                }
269                13 => {
270                    let v = (*obj).ptr as *mut f64;
271                    print!("{}", *v);
272                }
273                15 => {
274                    let s = CStr::from_ptr((*obj).ptr as *const c_char);
275                    match s.to_str() {
276                        Ok(s) => print!("{}", s),
277                        Err(_) => print!("InvalidUTF8String"),
278                    }
279                }
280                17 => {
281                    print!("Any")
282                }
283                _ => {
284                    print!("Unknown(id:{})", (*obj).id);
285                }
286            }
287        }
288    }
289}
290pub(crate) extern "C" fn append(l: i64, ptr: *mut Any) -> *mut c_char {
291    let mut s = String::new();
292    for i in 0..l {
293        let obj = unsafe { (ptr).offset(i as isize) };
294        unsafe {
295            match (*obj).id {
296                0 => {
297                    s.push_str("Unit");
298                }
299                1 => {
300                    let b = (*obj).ptr as i8;
301                    s.push_str(&format!("{}", b == 1));
302                }
303                3 => {
304                    let value = (*obj).ptr as i8;
305                    s.push_str(&format!("{}", value));
306                }
307                5 => {
308                    let value = (*obj).ptr as i16;
309                    s.push_str(&format!("{}", value));
310                }
311                7 => {
312                    let value = (*obj).ptr as i32;
313                    s.push_str(&format!("{}", value));
314                }
315                9 => {
316                    let v = (*obj).ptr as i64;
317                    s.push_str(&format!("{}", v));
318                }
319                11 => {
320                    let v = (*obj).ptr as *const f32;
321                    s.push_str(&format!("{}", *v));
322                }
323                13 => {
324                    let v = (*obj).ptr as *mut f64;
325                    s.push_str(&format!("{}", *v));
326                }
327                15 => {
328                    let s0 = CStr::from_ptr((*obj).ptr as *const c_char);
329                    match s0.to_str() {
330                        Ok(str_val) => s.push_str(str_val),
331                        Err(_) => s.push_str("InvalidUTF8String"),
332                    }
333                }
334                17 => {
335                    s.push_str("Any");
336                }
337                _ => {
338                    s.push_str(&format!("Unknown(id:{})", (*obj).id));
339                }
340            }
341        }
342    }
343    s.push('\0');
344    let s = s.leak();
345    s.as_ptr() as *mut c_char
346}
347lazy_static! {
348    /// 多环境工作目录映射表,用于管理不同执行环境的工作目录
349    /// key: 环境标识符,value: 对应的工作目录路径
350    /// 支持并发场景下多个线程使用不同的工作目录
351    static ref WORKSPACES: Mutex<HashMap<String, String>> = Mutex::new(HashMap::new());
352
353    /// 全局线程句柄存储,用于管理所有通过spawn创建的线程
354    /// 可以通过wait函数等待所有线程完成
355    static ref THREAD_HANDLES: Mutex<Vec<JoinHandle<()>>> = Mutex::new(Vec::new());
356}
357/// 在指定环境的工作目录中执行PowerShell命令
358///
359/// # 参数
360/// * `key` - 环境标识符,用于区分不同的执行环境
361/// * `command` - 要执行的命令字符串
362///
363/// # 说明
364/// 该函数会在指定环境key对应的工作目录中执行命令
365/// 如果环境key不存在,则使用当前目录"./"作为默认工作目录
366/// 命令输出会直接继承到父进程的标准输出和标准错误流
367/// 支持并发场景下不同线程使用不同的工作目录
368pub(crate) extern "C" fn cmd(key: *mut c_char, command: *mut c_char) {
369    let key_str = unsafe { CStr::from_ptr(key).to_str().unwrap() };
370    let cmd = unsafe { CStr::from_ptr(command).to_str().unwrap() };
371
372    let workspaces = WORKSPACES.lock().unwrap();
373    let binding = "./".to_string();
374    let workspace = workspaces.get(key_str).unwrap_or(&binding);
375    #[allow(clippy::zombie_processes)]
376    Command::new("powershell")
377        .current_dir(workspace)
378        .arg("/C")
379        .arg(cmd)
380        .stdout(Stdio::inherit())
381        .stderr(Stdio::inherit())
382        .spawn()
383        .expect("Failed to execute command");
384}
385/// 为指定环境设置工作目录
386///
387/// # 参数
388/// * `key` - 环境标识符,用于区分不同的执行环境
389/// * `dir` - 新的工作目录路径
390///
391/// # 说明
392/// 该函数会为指定的环境key设置工作目录,不会影响其他环境的工作目录
393/// 支持并发场景下不同线程使用独立的工作目录
394/// 如果传入的目录路径无效,函数会panic
395pub(crate) extern "C" fn workspace(key: *mut c_char, dir: *mut c_char) {
396    let key_str = unsafe { CStr::from_ptr(key).to_str().unwrap() };
397    let dir_str = unsafe { CStr::from_ptr(dir).to_str().unwrap() };
398
399    // 验证目录是否存在
400    if !std::path::Path::new(dir_str).exists() {
401        panic!("Directory does not exist: {}", dir_str);
402    }
403
404    // 为指定环境设置工作目录
405    let mut workspaces = WORKSPACES.lock().unwrap();
406    workspaces.insert(key_str.to_string(), dir_str.to_string());
407}
408#[allow(unused)]
409pub extern "C" fn exit() {
410    std::process::exit(0);
411}
412#[allow(unused)]
413pub(crate) extern "C" fn get_env(key: *mut c_char) -> *mut c_char {
414    let key = unsafe { CStr::from_ptr(key).to_str().unwrap() };
415    let mut value = std::env::var(key).unwrap();
416    value.push('\0');
417    let value = value.leak();
418    value.as_ptr() as *mut c_char
419}
420#[allow(unused)]
421pub(crate) extern "C" fn set_env(key: *mut c_char, value: *mut c_char) {
422    let key = unsafe { CStr::from_ptr(key).to_str().unwrap() };
423    let value = unsafe { CStr::from_ptr(value).to_str().unwrap() };
424    std::env::set_var(key, value);
425}
426
427#[allow(unused)]
428pub(crate) extern "C" fn panic(ptr: *mut c_char) {
429    let s = unsafe { CStr::from_ptr(ptr).to_str().unwrap() };
430    eprintln!("\x1b[31mpanic: {}\x1b[0m", s);
431    std::process::exit(1);
432}
433
434#[no_mangle]
435pub extern "C" fn now() -> u64 {
436    SystemTime::now()
437        .duration_since(UNIX_EPOCH)
438        .unwrap_or_default() // 错误时返回0(例如系统时间早于Unix纪元)
439        .as_millis() as u64 // 转换为u64(C兼容)
440}
441
442// 定义一个类型安全的函数指针类型,用于C FFI
443pub type ExternFn = extern "C" fn(*const u8);
444
445/// 创建新线程并执行指定函数
446///
447/// # 参数
448/// * `func` - 要在新线程中执行的函数指针
449///
450/// # 说明
451/// 该函数会创建一个新线程来异步执行指定的函数,
452/// 线程句柄会被存储在全局变量中,可通过wait函数等待所有线程完成
453pub extern "C" fn spawn0(func: ExternFn, _env: *const c_char, name: *const c_char) {
454    let name = unsafe { CStr::from_ptr(name).to_str().unwrap() };
455    // 在新线程中异步执行函数
456    let handle = thread::spawn(move || {
457        func(name.as_ptr());
458    });
459
460    // 将线程句柄存储到全局变量中
461    let mut handles = THREAD_HANDLES.lock().unwrap();
462    handles.push(handle);
463}
464
465/// 等待所有通过spawn创建的线程完成
466///
467/// # 说明
468/// 该函数会阻塞当前线程,直到所有通过spawn函数创建的线程都执行完成
469/// 调用后会清空线程句柄列表
470pub extern "C" fn wait() {
471    let mut handles = THREAD_HANDLES.lock().unwrap();
472
473    // 等待所有线程完成
474    while let Some(handle) = handles.pop() {
475        if let Err(e) = handle.join() {
476            eprintln!("线程执行失败: {:?}", e);
477        }
478    }
479}
480
481pub extern "C" fn sleep(ms: u64) {
482    thread::sleep(Duration::from_millis(ms));
483}
484
485pub(crate) extern "C" fn string_equal(l: *const c_char, r: *const c_char) -> bool {
486    let l = unsafe { CStr::from_ptr(l).to_str().unwrap() };
487    let r = unsafe { CStr::from_ptr(r).to_str().unwrap() };
488    l.eq(r)
489}
490
491/// 从控制台读取一行输入(包括换行符)
492///
493/// # 返回值
494/// 返回读取到的字符串指针,包含换行符
495///
496/// # 说明
497/// 该函数会阻塞等待用户输入,直到用户按下回车键
498/// 返回的字符串包含换行符,需要调用方自行处理
499pub extern "C" fn read_line() -> *mut c_char {
500    let mut input = String::new();
501    match io::stdin().read_line(&mut input) {
502        Ok(_) => {
503            // 转换为C字符串并返回指针
504            match CString::new(input) {
505                Ok(c_string) => c_string.into_raw(),
506                Err(_) => {
507                    // 如果转换失败,返回空字符串
508                    CString::new("").unwrap().into_raw()
509                }
510            }
511        }
512        Err(_) => {
513            // 读取失败时返回空字符串
514            CString::new("").unwrap().into_raw()
515        }
516    }
517}
518
519/// 从控制台读取字符串输入(去除换行符)
520///
521/// # 返回值
522/// 返回读取到的字符串指针,已去除末尾换行符
523///
524/// # 说明
525/// 该函数会阻塞等待用户输入,直到用户按下回车键
526/// 返回的字符串已自动去除末尾的换行符
527pub extern "C" fn read_string() -> *mut c_char {
528    let mut input = String::new();
529    match io::stdin().read_line(&mut input) {
530        Ok(_) => {
531            // 去除末尾的换行符
532            let trimmed = input.trim_end().to_string();
533            match CString::new(trimmed) {
534                Ok(c_string) => c_string.into_raw(),
535                Err(_) => {
536                    // 如果转换失败,返回空字符串
537                    CString::new("").unwrap().into_raw()
538                }
539            }
540        }
541        Err(_) => {
542            // 读取失败时返回空字符串
543            CString::new("").unwrap().into_raw()
544        }
545    }
546}
547
548/// 从控制台读取64位整数输入
549///
550/// # 返回值
551/// 返回读取到的64位整数,如果解析失败返回0
552///
553/// # 说明
554/// 该函数会阻塞等待用户输入,直到用户按下回车键
555/// 会尝试将输入解析为64位整数,如果解析失败返回0
556pub extern "C" fn read_int64() -> i64 {
557    let mut input = String::new();
558    match io::stdin().read_line(&mut input) {
559        Ok(_) => {
560            // 去除换行符并尝试解析为i64
561            match input.trim().parse::<i64>() {
562                Ok(num) => num,
563                Err(_) => {
564                    eprintln!("警告: 输入的不是有效的整数,返回默认值 0");
565                    0
566                }
567            }
568        }
569        Err(_) => {
570            eprintln!("错误: 读取输入失败,返回默认值 0");
571            0
572        }
573    }
574}
575
576/// 从控制台读取双精度浮点数输入
577///
578/// # 返回值
579/// 返回读取到的双精度浮点数,如果解析失败返回0.0
580///
581/// # 说明
582/// 该函数会阻塞等待用户输入,直到用户按下回车键
583/// 会尝试将输入解析为双精度浮点数,如果解析失败返回0.0
584pub extern "C" fn read_double() -> f64 {
585    let mut input = String::new();
586    match io::stdin().read_line(&mut input) {
587        Ok(_) => {
588            // 去除换行符并尝试解析为f64
589            match input.trim().parse::<f64>() {
590                Ok(num) => num,
591                Err(_) => {
592                    eprintln!("警告: 输入的不是有效的浮点数,返回默认值 0.0");
593                    0.0
594                }
595            }
596        }
597        Err(_) => {
598            eprintln!("错误: 读取输入失败,返回默认值 0.0");
599            0.0
600        }
601    }
602}
603/// 从控制台读取单精度浮点数输入
604///
605/// # 返回值
606/// 返回读取到的单精度浮点数,如果解析失败返回0.0
607///
608/// # 说明
609/// 该函数会阻塞等待用户输入,直到用户按下回车键
610/// 会尝试将输入解析为双精度浮点数,如果解析失败返回0.0
611pub extern "C" fn read_float() -> f32 {
612    let mut input = String::new();
613    match io::stdin().read_line(&mut input) {
614        Ok(_) => {
615            // 去除换行符并尝试解析为f64
616            match input.trim().parse::<f32>() {
617                Ok(num) => num,
618                Err(_) => {
619                    eprintln!("警告: 输入的不是有效的浮点数,返回默认值 0.0");
620                    0.0
621                }
622            }
623        }
624        Err(_) => {
625            eprintln!("错误: 读取输入失败,返回默认值 0.0");
626            0.0
627        }
628    }
629}