bloqade_lanes_bytecode/ffi/
validate.rs

1use std::os::raw::c_char;
2
3use bloqade_lanes_bytecode_core::bytecode::validate;
4
5use super::error::{BlqdStatus, clear_last_error, set_last_error};
6use super::handles::{BLQDArchSpec, BLQDProgram, BLQDValidationErrors};
7
8/// Structural validation (arity bounds, initial_fill ordering, etc.)
9#[unsafe(no_mangle)]
10pub unsafe extern "C" fn blqd_validate_structure(
11    prog: *const BLQDProgram,
12    out: *mut *mut BLQDValidationErrors,
13) -> BlqdStatus {
14    clear_last_error();
15
16    if prog.is_null() || out.is_null() {
17        set_last_error("null pointer argument");
18        return BlqdStatus::ErrNullPtr;
19    }
20
21    let prog = unsafe { &*prog };
22    let errors = validate::validate_structure(&prog.inner);
23    let status = if errors.is_empty() {
24        BlqdStatus::Ok
25    } else {
26        BlqdStatus::ErrValidation
27    };
28    let handle = Box::new(BLQDValidationErrors::from_errors(errors));
29    unsafe { *out = Box::into_raw(handle) };
30    status
31}
32
33/// Architecture-dependent validation (addresses + capability constraints).
34#[unsafe(no_mangle)]
35pub unsafe extern "C" fn blqd_validate_addresses(
36    prog: *const BLQDProgram,
37    arch: *const BLQDArchSpec,
38    out: *mut *mut BLQDValidationErrors,
39) -> BlqdStatus {
40    clear_last_error();
41
42    if prog.is_null() || arch.is_null() || out.is_null() {
43        set_last_error("null pointer argument");
44        return BlqdStatus::ErrNullPtr;
45    }
46
47    let prog = unsafe { &*prog };
48    let arch = unsafe { &*arch };
49    let errors = validate::validate_arch_constraints(&prog.inner, &arch.inner);
50    let status = if errors.is_empty() {
51        BlqdStatus::Ok
52    } else {
53        BlqdStatus::ErrValidation
54    };
55    let handle = Box::new(BLQDValidationErrors::from_errors(errors));
56    unsafe { *out = Box::into_raw(handle) };
57    status
58}
59
60/// Stack type simulation.
61#[unsafe(no_mangle)]
62pub unsafe extern "C" fn blqd_simulate_stack(
63    prog: *const BLQDProgram,
64    out: *mut *mut BLQDValidationErrors,
65) -> BlqdStatus {
66    clear_last_error();
67
68    if prog.is_null() || out.is_null() {
69        set_last_error("null pointer argument");
70        return BlqdStatus::ErrNullPtr;
71    }
72
73    let prog = unsafe { &*prog };
74    let errors = validate::simulate_stack(&prog.inner, None);
75    let status = if errors.is_empty() {
76        BlqdStatus::Ok
77    } else {
78        BlqdStatus::ErrValidation
79    };
80    let handle = Box::new(BLQDValidationErrors::from_errors(errors));
81    unsafe { *out = Box::into_raw(handle) };
82    status
83}
84
85/// Number of errors in the handle.
86#[unsafe(no_mangle)]
87pub unsafe extern "C" fn blqd_validation_errors_count(errs: *const BLQDValidationErrors) -> u32 {
88    if errs.is_null() {
89        return 0;
90    }
91    let errs = unsafe { &*errs };
92    errs.errors.len() as u32
93}
94
95/// Error message at index. Returns NULL if index is out of range.
96/// Pointer is valid until the handle is freed.
97#[unsafe(no_mangle)]
98pub unsafe extern "C" fn blqd_validation_error_message(
99    errs: *const BLQDValidationErrors,
100    index: u32,
101) -> *const c_char {
102    if errs.is_null() {
103        return std::ptr::null();
104    }
105    let errs = unsafe { &*errs };
106    match errs.messages.get(index as usize) {
107        Some(cstr) => cstr.as_ptr(),
108        None => std::ptr::null(),
109    }
110}
111
112/// Free a validation errors handle.
113#[unsafe(no_mangle)]
114pub unsafe extern "C" fn blqd_validation_errors_free(errs: *mut BLQDValidationErrors) {
115    if !errs.is_null() {
116        drop(unsafe { Box::from_raw(errs) });
117    }
118}