pipeline_script/core/
builtin.rs

1use std::collections::HashMap;
2use std::ffi::{c_char, CStr};
3use std::process::{Command, Stdio};
4use std::sync::Mutex;
5use std::thread::{self, JoinHandle};
6use std::time::{Duration, SystemTime, UNIX_EPOCH};
7
8use lazy_static::lazy_static;
9
10#[repr(C)]
11pub struct Array {
12    len: i64,
13    ptr: *mut Any,
14}
15#[repr(C)]
16pub struct Any {
17    id: i32,
18    ptr: *mut i8,
19}
20#[allow(unused)]
21pub extern "C" fn len(target: Array) -> i64 {
22    target.len
23}
24pub extern "C" fn println(obj: Any) {
25    unsafe {
26        match obj.id {
27            0 => {
28                print!("Unit")
29            }
30            1 => {
31                let b = obj.ptr as *mut bool;
32                print!("{}", *b);
33            }
34            3 => {
35                let value = obj.ptr as i8;
36                print!("{}", value);
37            }
38            5 => {
39                let value = obj.ptr as i16;
40                print!("{}", value);
41            }
42            7 => {
43                let v = obj.ptr as i32;
44                print!("{}", v);
45            }
46            9 => {
47                let v = obj.ptr as i64;
48                print!("{}", v);
49            }
50            11 => {
51                let v = obj.ptr as *mut f32;
52                print!("{}", *v);
53            }
54            13 => {
55                let v = obj.ptr as *mut f64;
56                print!("{}", *v);
57            }
58            15 => {
59                let s = CStr::from_ptr(obj.ptr as *const c_char);
60                print!("{}", s.to_str().unwrap());
61            }
62
63            t => todo!("{t}"),
64        }
65    }
66    // }
67    println!()
68}
69#[allow(unused)]
70pub extern "C" fn print(obj: Array) {
71    for i in 0..obj.len {
72        let obj = unsafe { (obj.ptr).offset(i as isize) };
73        unsafe {
74            match (*obj).id {
75                0 => {
76                    print!("Unit")
77                }
78                3 => {
79                    let value = (*obj).ptr as i32;
80                    print!("{}", value);
81                }
82                4 => {
83                    let v = (*obj).ptr as i64;
84                    print!("{}", v);
85                }
86                7 => {
87                    let s = CStr::from_ptr((*obj).ptr as *const c_char);
88                    print!("{}", s.to_str().unwrap());
89                }
90                t => todo!("{t}"),
91            }
92        }
93    }
94}
95pub extern "C" fn append(obj: Array) -> *mut c_char {
96    let mut s = String::new();
97    for i in 0..obj.len {
98        let obj = unsafe { (obj.ptr).offset(i as isize) };
99        unsafe {
100            match (*obj).id {
101                0 => {
102                    s.push_str("Unit");
103                }
104                3 => {
105                    let value = (*obj).ptr as i32;
106                    s.push_str(&format!("{}", value));
107                }
108                4 => {
109                    let v = (*obj).ptr as i64;
110                    s.push_str(&format!("{}", v));
111                }
112                7 => {
113                    let s0 = CStr::from_ptr((*obj).ptr as *const c_char);
114                    s.push_str(s0.to_str().unwrap());
115                }
116                t => todo!("{t}"),
117            }
118        }
119    }
120    s.push('\0');
121    let s = s.leak();
122    s.as_ptr() as *mut c_char
123}
124lazy_static! {
125    /// 多环境工作目录映射表,用于管理不同执行环境的工作目录
126    /// key: 环境标识符,value: 对应的工作目录路径
127    /// 支持并发场景下多个线程使用不同的工作目录
128    static ref WORKSPACES: Mutex<HashMap<String, String>> = Mutex::new(HashMap::new());
129
130    /// 全局线程句柄存储,用于管理所有通过spawn创建的线程
131    /// 可以通过wait函数等待所有线程完成
132    static ref THREAD_HANDLES: Mutex<Vec<JoinHandle<()>>> = Mutex::new(Vec::new());
133}
134/// 在指定环境的工作目录中执行PowerShell命令
135///
136/// # 参数
137/// * `key` - 环境标识符,用于区分不同的执行环境
138/// * `command` - 要执行的命令字符串
139///
140/// # 说明
141/// 该函数会在指定环境key对应的工作目录中执行命令
142/// 如果环境key不存在,则使用当前目录"./"作为默认工作目录
143/// 命令输出会直接继承到父进程的标准输出和标准错误流
144/// 支持并发场景下不同线程使用不同的工作目录
145pub extern "C" fn cmd(key: *mut c_char, command: *mut c_char) {
146    let key_str = unsafe { CStr::from_ptr(key).to_str().unwrap() };
147    let cmd = unsafe { CStr::from_ptr(command).to_str().unwrap() };
148
149    let workspaces = WORKSPACES.lock().unwrap();
150    let binding = "./".to_string();
151    let workspace = workspaces.get(key_str).unwrap_or(&binding);
152
153    Command::new("powershell")
154        .current_dir(workspace)
155        .arg("/C")
156        .arg(cmd)
157        .stdout(Stdio::inherit())
158        .stderr(Stdio::inherit())
159        .output()
160        .expect("Failed to execute command");
161}
162/// 为指定环境设置工作目录
163///
164/// # 参数
165/// * `key` - 环境标识符,用于区分不同的执行环境
166/// * `dir` - 新的工作目录路径
167///
168/// # 说明
169/// 该函数会为指定的环境key设置工作目录,不会影响其他环境的工作目录
170/// 支持并发场景下不同线程使用独立的工作目录
171/// 如果传入的目录路径无效,函数会panic
172pub extern "C" fn workspace(key: *mut c_char, dir: *mut c_char) {
173    let key_str = unsafe { CStr::from_ptr(key).to_str().unwrap() };
174    let dir_str = unsafe { CStr::from_ptr(dir).to_str().unwrap() };
175
176    // 验证目录是否存在
177    if !std::path::Path::new(dir_str).exists() {
178        panic!("Directory does not exist: {}", dir_str);
179    }
180
181    // 为指定环境设置工作目录
182    let mut workspaces = WORKSPACES.lock().unwrap();
183    workspaces.insert(key_str.to_string(), dir_str.to_string());
184}
185#[allow(unused)]
186pub extern "C" fn exit() {
187    std::process::exit(0);
188}
189#[allow(unused)]
190pub extern "C" fn get_env(key: *mut c_char) -> *mut c_char {
191    let key = unsafe { CStr::from_ptr(key).to_str().unwrap() };
192    let mut value = std::env::var(key).unwrap();
193    value.push('\0');
194    let value = value.leak();
195    value.as_ptr() as *mut c_char
196}
197#[allow(unused)]
198pub extern "C" fn set_env(key: *mut c_char, value: *mut c_char) {
199    let key = unsafe { CStr::from_ptr(key).to_str().unwrap() };
200    let value = unsafe { CStr::from_ptr(value).to_str().unwrap() };
201    std::env::set_var(key, value);
202}
203
204#[allow(unused)]
205pub extern "C" fn panic(ptr: *mut c_char) {
206    let s = unsafe { CStr::from_ptr(ptr).to_str().unwrap() };
207    eprintln!("\x1b[31mpanic: {}\x1b[0m", s);
208    std::process::exit(1);
209}
210
211#[no_mangle]
212pub extern "C" fn now() -> u64 {
213    SystemTime::now()
214        .duration_since(UNIX_EPOCH)
215        .unwrap_or_default() // 错误时返回0(例如系统时间早于Unix纪元)
216        .as_millis() as u64 // 转换为u64(C兼容)
217}
218
219// 定义一个类型安全的函数指针类型,用于C FFI
220pub type ExternFn = extern "C" fn();
221
222/// 创建新线程并执行指定函数
223///
224/// # 参数
225/// * `func` - 要在新线程中执行的函数指针
226///
227/// # 说明
228/// 该函数会创建一个新线程来异步执行指定的函数,
229/// 线程句柄会被存储在全局变量中,可通过wait函数等待所有线程完成
230pub extern "C" fn spawn(func: ExternFn) {
231    // 在新线程中异步执行函数
232    let handle = thread::spawn(move || {
233        func();
234    });
235
236    // 将线程句柄存储到全局变量中
237    let mut handles = THREAD_HANDLES.lock().unwrap();
238    handles.push(handle);
239}
240
241/// 等待所有通过spawn创建的线程完成
242///
243/// # 说明
244/// 该函数会阻塞当前线程,直到所有通过spawn函数创建的线程都执行完成
245/// 调用后会清空线程句柄列表
246pub extern "C" fn wait() {
247    let mut handles = THREAD_HANDLES.lock().unwrap();
248
249    // 等待所有线程完成
250    while let Some(handle) = handles.pop() {
251        if let Err(e) = handle.join() {
252            eprintln!("线程执行失败: {:?}", e);
253        }
254    }
255}
256
257pub extern "C" fn sleep(ms: u64) {
258    thread::sleep(Duration::from_millis(ms));
259}