use log::debug;
use std::cell::RefCell;
use std::clone::Clone;
use std::ffi::CString;
use std::rc::Rc;
use z3_sys::*;
use crate::{Config, ContextHandle};
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct ContextInternal(pub(crate) Z3_context);
impl Drop for ContextInternal {
fn drop(&mut self) {
unsafe { Z3_del_context(self.0) };
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Context {
pub(crate) z3_ctx: Rc<ContextInternal>,
}
impl Context {
pub fn thread_local() -> Context {
DEFAULT_CONTEXT.with(|f| f.borrow().clone())
}
pub(crate) fn set_thread_local(ctx: &Context) {
DEFAULT_CONTEXT.with(|f| {
*f.borrow_mut() = ctx.clone();
});
}
pub(crate) fn new(cfg: &Config) -> Context {
Context {
z3_ctx: unsafe {
let p = Z3_mk_context_rc(cfg.z3_cfg).unwrap();
debug!("new context {p:p}");
Z3_set_error_handler(p, None);
Rc::new(ContextInternal(p))
},
}
}
pub unsafe fn from_raw(z3_ctx: Z3_context) -> Context {
debug!("from_raw context {z3_ctx:p}");
Context {
z3_ctx: Rc::new(ContextInternal(z3_ctx)),
}
}
pub fn get_z3_context(&self) -> Z3_context {
self.z3_ctx.0
}
pub fn interrupt(&self) {
self.handle().interrupt();
}
pub fn handle(&self) -> ContextHandle<'_> {
ContextHandle { ctx: self }
}
pub fn update_param_value(&mut self, k: &str, v: &str) {
let ks = CString::new(k).unwrap();
let vs = CString::new(v).unwrap();
unsafe { Z3_update_param_value(self.z3_ctx.0, ks.as_ptr(), vs.as_ptr()) };
}
pub fn update_bool_param_value(&mut self, k: &str, v: bool) {
self.update_param_value(k, if v { "true" } else { "false" });
}
}
impl ContextHandle<'_> {
pub fn interrupt(&self) {
unsafe {
Z3_interrupt(self.ctx.z3_ctx.0);
}
}
}
unsafe impl Sync for ContextHandle<'_> {}
unsafe impl Send for ContextHandle<'_> {}
thread_local! {
static DEFAULT_CONTEXT: RefCell<Context> = RefCell::new(Context::new(&Config::new()));
}