pipeline_script/core/
builtin.rs

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