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) — prefer
62/// [`lanes_simulate_stack_with_arch`], which enables the arch-dependent
63/// lane-group checks (consistency, bus membership, AOD geometry).
64#[unsafe(no_mangle)]
65pub unsafe extern "C" fn lanes_simulate_stack(
66    prog: *const LANESProgram,
67    out: *mut *mut LANESValidationErrors,
68) -> LanesStatus {
69    unsafe { lanes_simulate_stack_with_arch(prog, std::ptr::null(), out) }
70}
71
72/// Stack type simulation with arch-dependent lane/location group checks
73/// (consistency, bus membership, AOD complete-grid geometry).
74///
75/// `arch` may be NULL, in which case group checks degrade to duplicate
76/// detection only (the [`lanes_simulate_stack`] behavior).
77#[unsafe(no_mangle)]
78pub unsafe extern "C" fn lanes_simulate_stack_with_arch(
79    prog: *const LANESProgram,
80    arch: *const LANESArchSpec,
81    out: *mut *mut LANESValidationErrors,
82) -> LanesStatus {
83    clear_last_error();
84
85    if prog.is_null() || out.is_null() {
86        set_last_error("null pointer argument");
87        return LanesStatus::ErrNullPtr;
88    }
89
90    let prog = unsafe { &*prog };
91    let arch = if arch.is_null() {
92        None
93    } else {
94        Some(unsafe { &(*arch).inner })
95    };
96    let errors = validate::simulate_stack(&prog.inner, arch);
97    let status = if errors.is_empty() {
98        LanesStatus::Ok
99    } else {
100        LanesStatus::ErrValidation
101    };
102    let handle = Box::new(LANESValidationErrors::from_errors(errors));
103    unsafe { *out = Box::into_raw(handle) };
104    status
105}
106
107/// Number of errors in the handle.
108#[unsafe(no_mangle)]
109pub unsafe extern "C" fn lanes_validation_errors_count(errs: *const LANESValidationErrors) -> u32 {
110    if errs.is_null() {
111        return 0;
112    }
113    let errs = unsafe { &*errs };
114    errs.errors.len() as u32
115}
116
117/// Error message at index. Returns NULL if index is out of range.
118/// Pointer is valid until the handle is freed.
119#[unsafe(no_mangle)]
120pub unsafe extern "C" fn lanes_validation_error_message(
121    errs: *const LANESValidationErrors,
122    index: u32,
123) -> *const c_char {
124    if errs.is_null() {
125        return std::ptr::null();
126    }
127    let errs = unsafe { &*errs };
128    match errs.messages.get(index as usize) {
129        Some(cstr) => cstr.as_ptr(),
130        None => std::ptr::null(),
131    }
132}
133
134/// Free a validation errors handle.
135#[unsafe(no_mangle)]
136pub unsafe extern "C" fn lanes_validation_errors_free(errs: *mut LANESValidationErrors) {
137    if !errs.is_null() {
138        drop(unsafe { Box::from_raw(errs) });
139    }
140}