bloqade_lanes_bytecode/ffi/
program.rs1use std::ffi::{CStr, CString};
2use std::os::raw::c_char;
3use std::slice;
4
5use bloqade_lanes_bytecode_core::bytecode::program::Program;
6use bloqade_lanes_bytecode_core::bytecode::text;
7
8use super::error::{BlqdStatus, clear_last_error, set_last_error};
9use super::handles::BLQDProgram;
10
11#[unsafe(no_mangle)]
13pub unsafe extern "C" fn blqd_program_from_binary(
14 data: *const u8,
15 len: usize,
16 out: *mut *mut BLQDProgram,
17) -> BlqdStatus {
18 clear_last_error();
19
20 if data.is_null() || out.is_null() {
21 set_last_error("null pointer argument");
22 return BlqdStatus::ErrNullPtr;
23 }
24
25 let bytes = unsafe { slice::from_raw_parts(data, len) };
26
27 match Program::from_binary(bytes) {
28 Ok(program) => {
29 let handle = Box::new(BLQDProgram { inner: program });
30 unsafe { *out = Box::into_raw(handle) };
31 BlqdStatus::Ok
32 }
33 Err(e) => {
34 set_last_error(e.to_string());
35 BlqdStatus::ErrDecode
36 }
37 }
38}
39
40#[unsafe(no_mangle)]
43pub unsafe extern "C" fn blqd_program_to_binary(
44 prog: *const BLQDProgram,
45 out_data: *mut *mut u8,
46 out_len: *mut usize,
47) -> BlqdStatus {
48 clear_last_error();
49
50 if prog.is_null() || out_data.is_null() || out_len.is_null() {
51 set_last_error("null pointer argument");
52 return BlqdStatus::ErrNullPtr;
53 }
54
55 let prog = unsafe { &*prog };
56 let bytes = prog.inner.to_binary();
57 let len = bytes.len();
58 let boxed = bytes.into_boxed_slice();
59 let ptr = Box::into_raw(boxed) as *mut u8;
60
61 unsafe {
62 *out_data = ptr;
63 *out_len = len;
64 }
65 BlqdStatus::Ok
66}
67
68#[unsafe(no_mangle)]
70pub unsafe extern "C" fn blqd_program_from_text(
71 text_ptr: *const c_char,
72 out: *mut *mut BLQDProgram,
73) -> BlqdStatus {
74 clear_last_error();
75
76 if text_ptr.is_null() || out.is_null() {
77 set_last_error("null pointer argument");
78 return BlqdStatus::ErrNullPtr;
79 }
80
81 let c_str = unsafe { CStr::from_ptr(text_ptr) };
82 let source = match c_str.to_str() {
83 Ok(s) => s,
84 Err(e) => {
85 set_last_error(format!("invalid UTF-8: {}", e));
86 return BlqdStatus::ErrIo;
87 }
88 };
89
90 match text::parse(source) {
91 Ok(program) => {
92 let handle = Box::new(BLQDProgram { inner: program });
93 unsafe { *out = Box::into_raw(handle) };
94 BlqdStatus::Ok
95 }
96 Err(e) => {
97 set_last_error(e.to_string());
98 BlqdStatus::ErrParse
99 }
100 }
101}
102
103#[unsafe(no_mangle)]
106pub unsafe extern "C" fn blqd_program_to_text(
107 prog: *const BLQDProgram,
108 out_text: *mut *mut c_char,
109) -> BlqdStatus {
110 clear_last_error();
111
112 if prog.is_null() || out_text.is_null() {
113 set_last_error("null pointer argument");
114 return BlqdStatus::ErrNullPtr;
115 }
116
117 let prog = unsafe { &*prog };
118 let text_out = text::print(&prog.inner);
119
120 match CString::new(text_out) {
121 Ok(cstr) => {
122 unsafe { *out_text = cstr.into_raw() };
123 BlqdStatus::Ok
124 }
125 Err(e) => {
126 set_last_error(format!("text contains null byte: {}", e));
127 BlqdStatus::ErrIo
128 }
129 }
130}
131
132#[unsafe(no_mangle)]
134pub unsafe extern "C" fn blqd_program_instruction_count(prog: *const BLQDProgram) -> u32 {
135 if prog.is_null() {
136 return 0;
137 }
138 let prog = unsafe { &*prog };
139 prog.inner.instructions.len() as u32
140}
141
142#[unsafe(no_mangle)]
144pub unsafe extern "C" fn blqd_program_version(
145 prog: *const BLQDProgram,
146 major: *mut u16,
147 minor: *mut u16,
148) {
149 if prog.is_null() || major.is_null() || minor.is_null() {
150 return;
151 }
152 let prog = unsafe { &*prog };
153 unsafe {
154 *major = prog.inner.version.major;
155 *minor = prog.inner.version.minor;
156 }
157}
158
159#[unsafe(no_mangle)]
161pub unsafe extern "C" fn blqd_program_free(prog: *mut BLQDProgram) {
162 if !prog.is_null() {
163 drop(unsafe { Box::from_raw(prog) });
164 }
165}