pipeline_script/core/
builtin.rs

1use std::collections::HashMap;
2use std::ffi::{c_char, 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}
27pub extern "C" fn println(l: i64, ptr: *mut Any) {
28    for i in 0..l {
29        let obj = unsafe { (ptr).offset(i as isize) };
30        unsafe {
31            match (*obj).id {
32                0 => {
33                    print!("Unit")
34                }
35                1 => {
36                    let b = (*obj).ptr as *mut bool;
37                    print!("{}", *b);
38                }
39                3 => {
40                    let value = (*obj).ptr as i8;
41                    print!("{}", value);
42                }
43                5 => {
44                    let value = (*obj).ptr as i16;
45                    print!("{}", value);
46                }
47                7 => {
48                    let v = (*obj).ptr as i32;
49                    print!("{}", v);
50                }
51                9 => {
52                    let v = (*obj).ptr as i64;
53                    print!("{}", v);
54                }
55                11 => {
56                    let v = (*obj).ptr as *mut f32;
57                    print!("{}", *v);
58                }
59                13 => {
60                    let v = (*obj).ptr as *mut f64;
61                    print!("{}", *v);
62                }
63                15 => {
64                    let s = CStr::from_ptr((*obj).ptr as *const c_char);
65                    print!("{}", s.to_str().unwrap());
66                }
67                t => todo!("{t}"),
68            }
69            if i < l - 1 {
70                print!("\t")
71            }
72        }
73    }
74    println!()
75}
76#[allow(unused)]
77pub extern "C" fn print(obj: Array) {
78    for i in 0..obj.len {
79        let obj = unsafe { (obj.ptr).offset(i as isize) };
80        unsafe {
81            match (*obj).id {
82                0 => {
83                    print!("Unit")
84                }
85                3 => {
86                    let value = (*obj).ptr as i32;
87                    print!("{}", value);
88                }
89                4 => {
90                    let v = (*obj).ptr as i64;
91                    print!("{}", v);
92                }
93                7 => {
94                    let s = CStr::from_ptr((*obj).ptr as *const c_char);
95                    print!("{}", s.to_str().unwrap());
96                }
97                t => todo!("{t}"),
98            }
99        }
100    }
101}
102pub extern "C" fn append(l: i64, ptr: *mut Any) -> *mut c_char {
103    let mut s = String::new();
104    for i in 0..l {
105        let obj = unsafe { (ptr).offset(i as isize) };
106        unsafe {
107            match (*obj).id {
108                0 => {
109                    s.push_str("Unit");
110                }
111                1 => {
112                    let b = (*obj).ptr as i8;
113                    s.push_str(&format!("{}", if b == 1 { true } else { false }));
114                }
115                7 => {
116                    let value = (*obj).ptr as i32;
117                    s.push_str(&format!("{}", value));
118                }
119                9 => {
120                    let v = (*obj).ptr as i64;
121                    s.push_str(&format!("{}", v));
122                }
123                11 => {
124                    let v = (*obj).ptr as *const f32;
125                    s.push_str(&format!("{}", *v));
126                }
127                13 => {
128                    let v = (*obj).ptr as *mut f64;
129                    s.push_str(&format!("{}", *v));
130                }
131                15 => {
132                    let s0 = CStr::from_ptr((*obj).ptr as *const c_char);
133                    s.push_str(s0.to_str().unwrap());
134                }
135                t => todo!("{t}"),
136            }
137        }
138    }
139    s.push('\0');
140    let s = s.leak();
141    s.as_ptr() as *mut c_char
142}
143lazy_static! {
144    /// 多环境工作目录映射表,用于管理不同执行环境的工作目录
145    /// key: 环境标识符,value: 对应的工作目录路径
146    /// 支持并发场景下多个线程使用不同的工作目录
147    static ref WORKSPACES: Mutex<HashMap<String, String>> = Mutex::new(HashMap::new());
148
149    /// 全局线程句柄存储,用于管理所有通过spawn创建的线程
150    /// 可以通过wait函数等待所有线程完成
151    static ref THREAD_HANDLES: Mutex<Vec<JoinHandle<()>>> = Mutex::new(Vec::new());
152}
153/// 在指定环境的工作目录中执行PowerShell命令
154///
155/// # 参数
156/// * `key` - 环境标识符,用于区分不同的执行环境
157/// * `command` - 要执行的命令字符串
158///
159/// # 说明
160/// 该函数会在指定环境key对应的工作目录中执行命令
161/// 如果环境key不存在,则使用当前目录"./"作为默认工作目录
162/// 命令输出会直接继承到父进程的标准输出和标准错误流
163/// 支持并发场景下不同线程使用不同的工作目录
164pub extern "C" fn cmd(key: *mut c_char, command: *mut c_char) {
165    let key_str = unsafe { CStr::from_ptr(key).to_str().unwrap() };
166    let cmd = unsafe { CStr::from_ptr(command).to_str().unwrap() };
167
168    let workspaces = WORKSPACES.lock().unwrap();
169    let binding = "./".to_string();
170    let workspace = workspaces.get(key_str).unwrap_or(&binding);
171
172    Command::new("powershell")
173        .current_dir(workspace)
174        .arg("/C")
175        .arg(cmd)
176        .stdout(Stdio::inherit())
177        .stderr(Stdio::inherit())
178        .spawn()
179        .expect("Failed to execute command"); // 非阻塞启动
180}
181/// 为指定环境设置工作目录
182///
183/// # 参数
184/// * `key` - 环境标识符,用于区分不同的执行环境
185/// * `dir` - 新的工作目录路径
186///
187/// # 说明
188/// 该函数会为指定的环境key设置工作目录,不会影响其他环境的工作目录
189/// 支持并发场景下不同线程使用独立的工作目录
190/// 如果传入的目录路径无效,函数会panic
191pub extern "C" fn workspace(key: *mut c_char, dir: *mut c_char) {
192    let key_str = unsafe { CStr::from_ptr(key).to_str().unwrap() };
193    let dir_str = unsafe { CStr::from_ptr(dir).to_str().unwrap() };
194
195    // 验证目录是否存在
196    if !std::path::Path::new(dir_str).exists() {
197        panic!("Directory does not exist: {}", dir_str);
198    }
199
200    // 为指定环境设置工作目录
201    let mut workspaces = WORKSPACES.lock().unwrap();
202    workspaces.insert(key_str.to_string(), dir_str.to_string());
203}
204#[allow(unused)]
205pub extern "C" fn exit() {
206    std::process::exit(0);
207}
208#[allow(unused)]
209pub extern "C" fn get_env(key: *mut c_char) -> *mut c_char {
210    let key = unsafe { CStr::from_ptr(key).to_str().unwrap() };
211    let mut value = std::env::var(key).unwrap();
212    value.push('\0');
213    let value = value.leak();
214    value.as_ptr() as *mut c_char
215}
216#[allow(unused)]
217pub extern "C" fn set_env(key: *mut c_char, value: *mut c_char) {
218    let key = unsafe { CStr::from_ptr(key).to_str().unwrap() };
219    let value = unsafe { CStr::from_ptr(value).to_str().unwrap() };
220    std::env::set_var(key, value);
221}
222
223#[allow(unused)]
224pub extern "C" fn panic(ptr: *mut c_char) {
225    let s = unsafe { CStr::from_ptr(ptr).to_str().unwrap() };
226    eprintln!("\x1b[31mpanic: {}\x1b[0m", s);
227    std::process::exit(1);
228}
229
230#[no_mangle]
231pub extern "C" fn now() -> u64 {
232    SystemTime::now()
233        .duration_since(UNIX_EPOCH)
234        .unwrap_or_default() // 错误时返回0(例如系统时间早于Unix纪元)
235        .as_millis() as u64 // 转换为u64(C兼容)
236}
237
238// 定义一个类型安全的函数指针类型,用于C FFI
239pub type ExternFn = extern "C" fn();
240
241/// 创建新线程并执行指定函数
242///
243/// # 参数
244/// * `func` - 要在新线程中执行的函数指针
245///
246/// # 说明
247/// 该函数会创建一个新线程来异步执行指定的函数,
248/// 线程句柄会被存储在全局变量中,可通过wait函数等待所有线程完成
249pub extern "C" fn spawn(func: ExternFn) {
250    // 在新线程中异步执行函数
251    let handle = thread::spawn(move || {
252        func();
253    });
254
255    // 将线程句柄存储到全局变量中
256    let mut handles = THREAD_HANDLES.lock().unwrap();
257    handles.push(handle);
258}
259
260/// 等待所有通过spawn创建的线程完成
261///
262/// # 说明
263/// 该函数会阻塞当前线程,直到所有通过spawn函数创建的线程都执行完成
264/// 调用后会清空线程句柄列表
265pub extern "C" fn wait() {
266    let mut handles = THREAD_HANDLES.lock().unwrap();
267
268    // 等待所有线程完成
269    while let Some(handle) = handles.pop() {
270        if let Err(e) = handle.join() {
271            eprintln!("线程执行失败: {:?}", e);
272        }
273    }
274}
275
276pub extern "C" fn sleep(ms: u64) {
277    thread::sleep(Duration::from_millis(ms));
278}
279
280pub extern "C" fn string_equal(l: *const c_char, r: *const c_char) -> bool {
281    let l = unsafe { CStr::from_ptr(l).to_str().unwrap() };
282    let r = unsafe { CStr::from_ptr(r).to_str().unwrap() };
283    return l.eq(r);
284}
285
286/// 从控制台读取一行输入(包括换行符)
287///
288/// # 返回值
289/// 返回读取到的字符串指针,包含换行符
290///
291/// # 说明
292/// 该函数会阻塞等待用户输入,直到用户按下回车键
293/// 返回的字符串包含换行符,需要调用方自行处理
294pub extern "C" fn read_line() -> *mut c_char {
295    let mut input = String::new();
296    match io::stdin().read_line(&mut input) {
297        Ok(_) => {
298            // 转换为C字符串并返回指针
299            match CString::new(input) {
300                Ok(c_string) => c_string.into_raw(),
301                Err(_) => {
302                    // 如果转换失败,返回空字符串
303                    CString::new("").unwrap().into_raw()
304                }
305            }
306        }
307        Err(_) => {
308            // 读取失败时返回空字符串
309            CString::new("").unwrap().into_raw()
310        }
311    }
312}
313
314/// 从控制台读取字符串输入(去除换行符)
315///
316/// # 返回值
317/// 返回读取到的字符串指针,已去除末尾换行符
318///
319/// # 说明
320/// 该函数会阻塞等待用户输入,直到用户按下回车键
321/// 返回的字符串已自动去除末尾的换行符
322pub extern "C" fn read_string() -> *mut c_char {
323    let mut input = String::new();
324    match io::stdin().read_line(&mut input) {
325        Ok(_) => {
326            // 去除末尾的换行符
327            let trimmed = input.trim_end().to_string();
328            match CString::new(trimmed) {
329                Ok(c_string) => c_string.into_raw(),
330                Err(_) => {
331                    // 如果转换失败,返回空字符串
332                    CString::new("").unwrap().into_raw()
333                }
334            }
335        }
336        Err(_) => {
337            // 读取失败时返回空字符串
338            CString::new("").unwrap().into_raw()
339        }
340    }
341}
342
343/// 从控制台读取64位整数输入
344///
345/// # 返回值
346/// 返回读取到的64位整数,如果解析失败返回0
347///
348/// # 说明
349/// 该函数会阻塞等待用户输入,直到用户按下回车键
350/// 会尝试将输入解析为64位整数,如果解析失败返回0
351pub extern "C" fn read_int64() -> i64 {
352    let mut input = String::new();
353    match io::stdin().read_line(&mut input) {
354        Ok(_) => {
355            // 去除换行符并尝试解析为i64
356            match input.trim().parse::<i64>() {
357                Ok(num) => num,
358                Err(_) => {
359                    eprintln!("警告: 输入的不是有效的整数,返回默认值 0");
360                    0
361                }
362            }
363        }
364        Err(_) => {
365            eprintln!("错误: 读取输入失败,返回默认值 0");
366            0
367        }
368    }
369}
370
371/// 从控制台读取双精度浮点数输入
372///
373/// # 返回值
374/// 返回读取到的双精度浮点数,如果解析失败返回0.0
375///
376/// # 说明
377/// 该函数会阻塞等待用户输入,直到用户按下回车键
378/// 会尝试将输入解析为双精度浮点数,如果解析失败返回0.0
379pub extern "C" fn read_double() -> f64 {
380    let mut input = String::new();
381    match io::stdin().read_line(&mut input) {
382        Ok(_) => {
383            // 去除换行符并尝试解析为f64
384            match input.trim().parse::<f64>() {
385                Ok(num) => num,
386                Err(_) => {
387                    eprintln!("警告: 输入的不是有效的浮点数,返回默认值 0.0");
388                    0.0
389                }
390            }
391        }
392        Err(_) => {
393            eprintln!("错误: 读取输入失败,返回默认值 0.0");
394            0.0
395        }
396    }
397}
398/// 从控制台读取单精度浮点数输入
399///
400/// # 返回值
401/// 返回读取到的单精度浮点数,如果解析失败返回0.0
402///
403/// # 说明
404/// 该函数会阻塞等待用户输入,直到用户按下回车键
405/// 会尝试将输入解析为双精度浮点数,如果解析失败返回0.0
406pub extern "C" fn read_float() -> f32 {
407    let mut input = String::new();
408    match io::stdin().read_line(&mut input) {
409        Ok(_) => {
410            // 去除换行符并尝试解析为f64
411            match input.trim().parse::<f32>() {
412                Ok(num) => num,
413                Err(_) => {
414                    eprintln!("警告: 输入的不是有效的浮点数,返回默认值 0.0");
415                    0.0
416                }
417            }
418        }
419        Err(_) => {
420            eprintln!("错误: 读取输入失败,返回默认值 0.0");
421            0.0
422        }
423    }
424}