pipeline_script/core/
builtin.rs

1use std::ffi::{c_char, CStr};
2use std::process::{Command, Stdio};
3use std::sync::Mutex;
4use std::thread::{self};
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/// 在指定工作目录中执行PowerShell命令
129///
130/// # 参数
131/// * `command` - 要执行的命令字符串
132///
133/// # 说明
134/// 该函数会在当前工作目录(由WORKSPACE变量指定)中执行命令
135/// 命令输出会直接继承到父进程的标准输出和标准错误流
136pub extern "C" fn cmd(command: *mut c_char) {
137    let cmd = unsafe { CStr::from_ptr(command).to_str().unwrap() };
138    let workspace = WORKSPACE.lock().unwrap();
139    Command::new("powershell")
140        .current_dir(workspace.as_str())
141        .arg("/C")
142        .arg(cmd)
143        .stdout(Stdio::inherit())
144        .stderr(Stdio::inherit())
145        .output()
146        .expect("Failed to execute command");
147}
148/// 切换当前工作目录
149///
150/// # 参数
151/// * `dir` - 新的工作目录路径
152///
153/// # 说明
154/// 该函数会更新全局工作目录变量,影响后续cmd函数的执行目录
155/// 如果传入的目录路径无效,函数会panic
156pub extern "C" fn workspace(dir: *mut c_char) {
157    let dir_str = unsafe { CStr::from_ptr(dir).to_str().unwrap() };
158
159    // 验证目录是否存在
160    if !std::path::Path::new(dir_str).exists() {
161        panic!("Directory does not exist: {}", dir_str);
162    }
163
164    // 更新全局工作目录
165    let mut workspace = WORKSPACE.lock().unwrap();
166    *workspace = dir_str.to_string();
167}
168#[allow(unused)]
169pub extern "C" fn exit() {
170    std::process::exit(0);
171}
172#[allow(unused)]
173pub extern "C" fn get_env(key: *mut c_char) -> *mut c_char {
174    let key = unsafe { CStr::from_ptr(key).to_str().unwrap() };
175    let mut value = std::env::var(key).unwrap();
176    value.push('\0');
177    let value = value.leak();
178    value.as_ptr() as *mut c_char
179}
180#[allow(unused)]
181pub extern "C" fn set_env(key: *mut c_char, value: *mut c_char) {
182    let key = unsafe { CStr::from_ptr(key).to_str().unwrap() };
183    let value = unsafe { CStr::from_ptr(value).to_str().unwrap() };
184    std::env::set_var(key, value);
185}
186
187#[allow(unused)]
188pub extern "C" fn panic(ptr: *mut c_char) {
189    let s = unsafe { CStr::from_ptr(ptr).to_str().unwrap() };
190    eprintln!("\x1b[31mpanic: {}\x1b[0m", s);
191    std::process::exit(1);
192}
193
194#[no_mangle]
195pub extern "C" fn now() -> u64 {
196    SystemTime::now()
197        .duration_since(UNIX_EPOCH)
198        .unwrap_or_default() // 错误时返回0(例如系统时间早于Unix纪元)
199        .as_millis() as u64 // 转换为u64(C兼容)
200}
201
202// 定义一个类型安全的函数指针类型,用于C FFI
203pub type ExternFn = extern "C" fn();
204
205pub extern "C" fn spawn(func: ExternFn) {
206    // 在新线程中异步执行函数
207    thread::spawn(move || {
208        func();
209    });
210}
211
212pub extern "C" fn sleep(ms: u64) {
213    thread::sleep(Duration::from_millis(ms));
214}