Skip to main content

bloqade_lanes_bytecode/ffi/
validate.rs

1use std::os::raw::c_char;
2
3use bloqade_lanes_bytecode_core::isa::validate;
4
5use super::error::{LanesStatus, clear_last_error, set_last_error};
6use super::handles::{LANESArchSpec, LANESProgram, LANESValidationErrors};
7
8/// Structural validation (arity bounds, initial_fill ordering, etc.)
9#[unsafe(no_mangle)]
10pub unsafe extern "C" fn lanes_validate_structure(
11    prog: *const LANESProgram,
12    out: *mut *mut LANESValidationErrors,
13) -> LanesStatus {
14    clear_last_error();
15
16    if prog.is_null() || out.is_null() {
17        set_last_error("null pointer argument");
18        return LanesStatus::ErrNullPtr;
19    }
20
21    let prog = unsafe { &*prog };
22    let errors = validate::validate_structure(&prog.inner);
23    let status = if errors.is_empty() {
24        LanesStatus::Ok
25    } else {
26        LanesStatus::ErrValidation
27    };
28    let handle = Box::new(LANESValidationErrors::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 lanes_validate_addresses(
36    prog: *const LANESProgram,
37    arch: *const LANESArchSpec,
38    out: *mut *mut LANESValidationErrors,
39) -> LanesStatus {
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 LanesStatus::ErrNullPtr;
45    }
46
47    let prog = unsafe { &*prog };
48    let arch = unsafe { &*arch };
49    let errors = validate::validate(&prog.inner, Some(&arch.inner));
50    let status = if errors.is_empty() {
51        LanesStatus::Ok
52    } else {
53        LanesStatus::ErrValidation
54    };
55    let handle = Box::new(LANESValidationErrors::from_errors(errors));
56    unsafe { *out = Box::into_raw(handle) };
57    status
58}
59
60/// Stack type simulation (underflow, type mismatches, and lane/location group
61/// checks). Runs without an arch spec (duplicate-only group checks).
62#[unsafe(no_mangle)]
63pub unsafe extern "C" fn lanes_simulate_stack(
64    prog: *const LANESProgram,
65    out: *mut *mut LANESValidationErrors,
66) -> LanesStatus {
67    clear_last_error();
68
69    if prog.is_null() || out.is_null() {
70        set_last_error("null pointer argument");
71        return LanesStatus::ErrNullPtr;
72    }
73
74    let prog = unsafe { &*prog };
75    let errors = validate::simulate_stack(&prog.inner, None);
76    let status = if errors.is_empty() {
77        LanesStatus::Ok
78    } else {
79        LanesStatus::ErrValidation
80    };
81    let handle = Box::new(LANESValidationErrors::from_errors(errors));
82    unsafe { *out = Box::into_raw(handle) };
83    status
84}
85
86/// Number of errors in the handle.
87#[unsafe(no_mangle)]
88pub unsafe extern "C" fn lanes_validation_errors_count(errs: *const LANESValidationErrors) -> u32 {
89    if errs.is_null() {
90        return 0;
91    }
92    let errs = unsafe { &*errs };
93    errs.errors.len() as u32
94}
95
96/// Error message at index. Returns NULL if index is out of range.
97/// Pointer is valid until the handle is freed.
98#[unsafe(no_mangle)]
99pub unsafe extern "C" fn lanes_validation_error_message(
100    errs: *const LANESValidationErrors,
101    index: u32,
102) -> *const c_char {
103    if errs.is_null() {
104        return std::ptr::null();
105    }
106    let errs = unsafe { &*errs };
107    match errs.messages.get(index as usize) {
108        Some(cstr) => cstr.as_ptr(),
109        None => std::ptr::null(),
110    }
111}
112
113/// Free a validation errors handle.
114#[unsafe(no_mangle)]
115pub unsafe extern "C" fn lanes_validation_errors_free(errs: *mut LANESValidationErrors) {
116    if !errs.is_null() {
117        drop(unsafe { Box::from_raw(errs) });
118    }
119}