z3/context.rs
1use log::debug;
2use std::cell::RefCell;
3use std::clone::Clone;
4use std::ffi::CString;
5use std::rc::Rc;
6use z3_sys::*;
7
8use crate::{Config, ContextHandle};
9
10/// A wrapper around [`Z3_context`] that enforces proper dropping behavior.
11/// All high-level code should instead use [`Context`]
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub(crate) struct ContextInternal(pub(crate) Z3_context);
14
15impl Drop for ContextInternal {
16 fn drop(&mut self) {
17 unsafe { Z3_del_context(self.0) };
18 }
19}
20
21/// Manager of all other Z3 objects, global configuration options, etc.
22///
23/// An application may use multiple Z3 contexts. Objects created in one context
24/// cannot be used in another one. However, several objects may be "translated" from
25/// one context to another.
26///
27/// While it is not safe to access Z3 objects from multiple threads, this library includes
28/// a safe structured abstraction for usage of Z3 objects across threads.
29/// See [`Synchronized`](crate::Synchronized).
30///
31/// z3.rs uses an implicit thread-local context by default, which is used in all operations.
32/// Most users will not need to create their own contexts or interact with contexts directly.
33///
34/// To use a context with a customized configuration (e.g. setting timeouts),
35/// use [`with_z3_config`](crate::with_z3_config).
36///
37/// Advanced users (e.g. those performing FFI with other Z3 bindings) can unsafely create their
38/// own contexts using [`Context::from_raw`], and then use them with [`with_z3_context`](crate::with_z3_context).
39///
40/// # See also:
41///
42/// - [`Config`]
43/// - [`with_z3_config`](crate::with_z3_config)
44/// - [`with_z3_context`](crate::with_z3_context)
45/// - [`Synchronized`](crate::Synchronized)
46/// - [`Translate`](crate::Translate)
47#[derive(PartialEq, Eq, Debug, Clone)]
48pub struct Context {
49 pub(crate) z3_ctx: Rc<ContextInternal>,
50}
51impl Context {
52 /// Returns a handle to the default thread-local [`Context`].
53 ///
54 /// This [`Context`] is used in all z3 operations.
55 /// Custom [`Context`]s are supported through [`with_z3_config`](crate::with_z3_config),
56 /// which allow for running a closure inside an environment with the provided [`Context`]
57 ///
58 /// # See also:
59 /// - [`with_z3_config`](crate::with_z3_config)
60 pub fn thread_local() -> Context {
61 DEFAULT_CONTEXT.with(|f| f.borrow().clone())
62 }
63
64 /// _Replaces_ the thread-local [`Context`] with a new one created from the given [`Config`].
65 /// This is useful if you want to use a specific configuration, but also want
66 /// to use the default thread-local context. Note that calling this function will
67 /// _replace_ the existing thread-local context. All existing [`Ast`]s and other Z3 objects
68 /// that were created using the previous thread-local context will still be valid, but cannot
69 /// be used with the new context without translation. You will generally want to call this
70 /// before you create any [`Ast`]s or other Z3 objects to avoid confusion. Also note that
71 /// since the [`Context`] is thread-local, this will only affect the current thread.
72 ///
73 /// # See also:
74 /// /// - [`Context::thread_local()`]
75 pub(crate) fn set_thread_local(ctx: &Context) {
76 DEFAULT_CONTEXT.with(|f| {
77 *f.borrow_mut() = ctx.clone();
78 });
79 }
80
81 /// Creates a new Z3 Context using the given configuration.
82 pub(crate) fn new(cfg: &Config) -> Context {
83 Context {
84 z3_ctx: unsafe {
85 let p = Z3_mk_context_rc(cfg.z3_cfg).unwrap();
86 debug!("new context {p:p}");
87 Z3_set_error_handler(p, None);
88 Rc::new(ContextInternal(p))
89 },
90 }
91 }
92
93 /// Construct a [`Context`] from a raw [`Z3_context`] pointer. This is mostly useful for
94 /// consumers who want to interoperate with Z3 contexts created through other means,
95 /// such as the C API or other bindings such as Python.
96 ///
97 /// # Safety
98 ///
99 /// The caller must ensure the pointer is valid and not already managed elsewhere.
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// use z3::ast::Bool;
105 /// use z3_sys::{Z3_mk_config, Z3_del_config, Z3_mk_context_rc};
106 /// use z3::Context;
107 ///
108 /// // Create a raw Z3_config using the low-level API
109 /// let cfg = unsafe { Z3_mk_config() }.unwrap();
110 /// let raw_ctx = unsafe { Z3_mk_context_rc(cfg) }.unwrap();
111 /// let ctx = unsafe { Context::from_raw(raw_ctx) };
112 /// // Use `ctx` as usual...
113 /// unsafe { Z3_del_config(cfg) };
114 /// let b = Bool::from_bool(true);
115 /// assert_eq!(b.as_bool(), Some(true));
116 /// ```
117 pub unsafe fn from_raw(z3_ctx: Z3_context) -> Context {
118 debug!("from_raw context {z3_ctx:p}");
119 Context {
120 z3_ctx: Rc::new(ContextInternal(z3_ctx)),
121 }
122 }
123
124 pub fn get_z3_context(&self) -> Z3_context {
125 self.z3_ctx.0
126 }
127
128 /// Interrupt a solver performing a satisfiability test, a tactic processing a goal, or simplify functions.
129 pub fn interrupt(&self) {
130 self.handle().interrupt();
131 }
132
133 /// Obtain a handle that can be used to interrupt computation from another thread.
134 ///
135 /// # See also:
136 ///
137 /// - [`ContextHandle`]
138 /// - [`ContextHandle::interrupt()`]
139 pub fn handle(&self) -> ContextHandle<'_> {
140 ContextHandle { ctx: self }
141 }
142
143 /// Update a global parameter.
144 ///
145 /// # See also
146 ///
147 /// - [`Context::update_bool_param_value()`]
148 pub fn update_param_value(&mut self, k: &str, v: &str) {
149 let ks = CString::new(k).unwrap();
150 let vs = CString::new(v).unwrap();
151 unsafe { Z3_update_param_value(self.z3_ctx.0, ks.as_ptr(), vs.as_ptr()) };
152 }
153
154 /// Update a global parameter.
155 ///
156 /// This is a helper function.
157 ///
158 /// # See also
159 ///
160 /// - [`Context::update_param_value()`]
161 pub fn update_bool_param_value(&mut self, k: &str, v: bool) {
162 self.update_param_value(k, if v { "true" } else { "false" });
163 }
164}
165
166impl ContextHandle<'_> {
167 /// Interrupt a solver performing a satisfiability test, a tactic processing a goal, or simplify functions.
168 pub fn interrupt(&self) {
169 unsafe {
170 Z3_interrupt(self.ctx.z3_ctx.0);
171 }
172 }
173}
174
175unsafe impl Sync for ContextHandle<'_> {}
176unsafe impl Send for ContextHandle<'_> {}
177
178thread_local! {
179 static DEFAULT_CONTEXT: RefCell<Context> = RefCell::new(Context::new(&Config::new()));
180}