use core::ffi::c_char;
use core::ptr;
use std::ffi::{CStr, CString};
use crate::cmd_context::{Session, run_smt2};
unsafe fn c_str<'a>(p: *const c_char) -> Option<&'a str> {
if p.is_null() {
return None;
}
unsafe { CStr::from_ptr(p) }.to_str().ok()
}
fn into_c_string(s: String) -> *mut c_char {
match CString::new(s) {
Ok(c) => c.into_raw(),
Err(_) => ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn z3rs_version() -> *const c_char {
concat!(env!("CARGO_PKG_VERSION"), "\0").as_ptr() as *const c_char
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn z3rs_eval_smtlib2_string(script: *const c_char) -> *mut c_char {
if script.is_null() {
return ptr::null_mut();
}
let text = match unsafe { CStr::from_ptr(script) }.to_str() {
Ok(s) => s,
Err(_) => return ptr::null_mut(),
};
let out = match run_smt2(text) {
Ok(lines) => lines.join("\n"),
Err(e) => alloc::format!("(error \"{e}\")"),
};
match CString::new(out) {
Ok(c) => c.into_raw(),
Err(_) => ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn z3rs_string_free(s: *mut c_char) {
if !s.is_null() {
drop(unsafe { CString::from_raw(s) });
}
}
pub struct Z3rsSession(Session);
#[unsafe(no_mangle)]
pub extern "C" fn z3rs_mk_session() -> *mut Z3rsSession {
Box::into_raw(Box::new(Z3rsSession(Session::new())))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn z3rs_session_eval(
s: *mut Z3rsSession,
script: *const c_char,
) -> *mut c_char {
if s.is_null() {
return ptr::null_mut();
}
let session = unsafe { &mut *s };
let Some(text) = (unsafe { c_str(script) }) else {
return ptr::null_mut();
};
let out = match session.0.eval(text) {
Ok(lines) => lines.join("\n"),
Err(e) => alloc::format!("(error \"{e}\")"),
};
into_c_string(out)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn z3rs_del_session(s: *mut Z3rsSession) {
if !s.is_null() {
drop(unsafe { Box::from_raw(s) });
}
}