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::isa::program::{from_binary, to_binary};
6use bloqade_lanes_bytecode_core::isa::{parse_text, to_text};
7
8use super::error::{LanesStatus, clear_last_error, set_last_error};
9use super::handles::LANESProgram;
10
11#[unsafe(no_mangle)]
13pub unsafe extern "C" fn lanes_program_from_binary(
14 data: *const u8,
15 len: usize,
16 out: *mut *mut LANESProgram,
17) -> LanesStatus {
18 clear_last_error();
19
20 if data.is_null() || out.is_null() {
21 set_last_error("null pointer argument");
22 return LanesStatus::ErrNullPtr;
23 }
24
25 let bytes = unsafe { slice::from_raw_parts(data, len) };
26
27 match from_binary(bytes) {
28 Ok(program) => {
29 let handle = Box::new(LANESProgram { inner: program });
30 unsafe { *out = Box::into_raw(handle) };
31 LanesStatus::Ok
32 }
33 Err(e) => {
34 set_last_error(e.to_string());
35 LanesStatus::ErrDecode
36 }
37 }
38}
39
40#[unsafe(no_mangle)]
43pub unsafe extern "C" fn lanes_program_to_binary(
44 prog: *const LANESProgram,
45 out_data: *mut *mut u8,
46 out_len: *mut usize,
47) -> LanesStatus {
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 LanesStatus::ErrNullPtr;
53 }
54
55 let prog = unsafe { &*prog };
56 let bytes = to_binary(&prog.inner);
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 LanesStatus::Ok
66}
67
68#[unsafe(no_mangle)]
70pub unsafe extern "C" fn lanes_program_from_text(
71 text_ptr: *const c_char,
72 out: *mut *mut LANESProgram,
73) -> LanesStatus {
74 clear_last_error();
75
76 if text_ptr.is_null() || out.is_null() {
77 set_last_error("null pointer argument");
78 return LanesStatus::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 LanesStatus::ErrIo;
87 }
88 };
89
90 match parse_text(source) {
91 Ok(program) => {
92 let handle = Box::new(LANESProgram { inner: program });
93 unsafe { *out = Box::into_raw(handle) };
94 LanesStatus::Ok
95 }
96 Err(e) => {
97 set_last_error(e.to_string());
98 LanesStatus::ErrParse
99 }
100 }
101}
102
103#[unsafe(no_mangle)]
106pub unsafe extern "C" fn lanes_program_to_text(
107 prog: *const LANESProgram,
108 out_text: *mut *mut c_char,
109) -> LanesStatus {
110 clear_last_error();
111
112 if prog.is_null() || out_text.is_null() {
113 set_last_error("null pointer argument");
114 return LanesStatus::ErrNullPtr;
115 }
116
117 let prog = unsafe { &*prog };
118 let text_out = to_text(&prog.inner);
119
120 match CString::new(text_out) {
121 Ok(cstr) => {
122 unsafe { *out_text = cstr.into_raw() };
123 LanesStatus::Ok
124 }
125 Err(e) => {
126 set_last_error(format!("text contains null byte: {}", e));
127 LanesStatus::ErrIo
128 }
129 }
130}
131
132#[unsafe(no_mangle)]
134pub unsafe extern "C" fn lanes_program_instruction_count(prog: *const LANESProgram) -> u32 {
135 if prog.is_null() {
136 return 0;
137 }
138 let prog = unsafe { &*prog };
139 prog.inner.code.len() as u32
140}
141
142#[unsafe(no_mangle)]
144pub unsafe extern "C" fn lanes_program_version(
145 prog: *const LANESProgram,
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.extra.version.major;
155 *minor = prog.inner.extra.version.minor;
156 }
157}
158
159#[unsafe(no_mangle)]
161pub unsafe extern "C" fn lanes_program_free(prog: *mut LANESProgram) {
162 if !prog.is_null() {
163 drop(unsafe { Box::from_raw(prog) });
164 }
165}