Skip to content

Commit

Permalink
Add FFIPointer helper type to manage Rust types exposed to C
Browse files Browse the repository at this point in the history
  • Loading branch information
Dekker1 committed Jun 27, 2024
1 parent 69a66c3 commit c30c0a6
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 152 deletions.
170 changes: 68 additions & 102 deletions crates/pindakaas-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,109 +93,82 @@ pub fn ipasir_solver_derive(input: TokenStream) -> TokenStream {
quote!()
};

let (term_callback, term_drop) = if opts.term_callback {
let term_callback = if opts.term_callback {
let term_cb = match opts.term_callback_ident {
Some(x) => quote! { self. #x },
None => quote! { self.term_cb },
};
(
quote! {
impl crate::solver::TermCallback for #ident {
fn set_terminate_callback<F: FnMut() -> crate::solver::SlvTermSignal + 'static>(
&mut self,
cb: Option<F>,
) {
if let Some(mut cb) = cb {
let wrapped_cb = move || -> std::ffi::c_int {
match cb() {
crate::solver::SlvTermSignal::Continue => std::ffi::c_int::from(0),
crate::solver::SlvTermSignal::Terminate => std::ffi::c_int::from(1),
}
};
let trampoline = crate::solver::libloading::get_trampoline0(&wrapped_cb);
let layout = std::alloc::Layout::for_value(&wrapped_cb);
let data = Box::leak(Box::new(wrapped_cb)) as *mut _ as *mut std::ffi::c_void;
if layout.size() != 0 {
// Otherwise nothing was leaked.
#term_cb = Some((data, layout));
}
unsafe {
#krate::ipasir_set_terminate(
#ptr,
data,
Some(trampoline),
)
}
} else {
if let Some((ptr, layout)) = #term_cb .take() {
unsafe { std::alloc::dealloc(ptr as *mut _, layout) };
quote! {
impl crate::solver::TermCallback for #ident {
fn set_terminate_callback<F: FnMut() -> crate::solver::SlvTermSignal + 'static>(
&mut self,
cb: Option<F>,
) {
if let Some(mut cb) = cb {
let wrapped_cb = move || -> std::ffi::c_int {
match cb() {
crate::solver::SlvTermSignal::Continue => std::ffi::c_int::from(0),
crate::solver::SlvTermSignal::Terminate => std::ffi::c_int::from(1),
}
unsafe { #krate::ipasir_set_terminate(#ptr, std::ptr::null_mut(), None) }
};
let trampoline = crate::solver::libloading::get_trampoline0(&wrapped_cb);
#term_cb = crate::solver::libloading::FFIPointer::new(wrapped_cb);
unsafe {
#krate::ipasir_set_terminate(
#ptr,
#term_cb .get_ptr(),
Some(trampoline),
)
}
} else {
#term_cb = crate::solver::libloading::FFIPointer::default();
unsafe { #krate::ipasir_set_terminate(#ptr, std::ptr::null_mut(), None) }
}
}
},
quote! {
if let Some((ptr, layout)) = #term_cb .take() {
unsafe { std::alloc::dealloc(ptr as *mut _, layout) };
}
},
)
}
}
} else {
(quote!(), quote!())
quote!()
};

let (learn_callback, learn_drop) = if opts.learn_callback {
let learn_callback = if opts.learn_callback {
let learn_cb = match opts.learn_callback_ident {
Some(x) => quote! { self. #x },
None => quote! { self.learn_cb },
};
(
quote! {
impl crate::solver::LearnCallback for #ident {
fn set_learn_callback<F: FnMut(&mut dyn Iterator<Item = crate::Lit>) + 'static>(
&mut self,
cb: Option<F>,
) {
const MAX_LEN: std::ffi::c_int = 512;
if let Some(mut cb) = cb {
let wrapped_cb = move |clause: *const i32| {
let mut iter = crate::solver::libloading::ExplIter(clause)
.map(|i: i32| crate::Lit(std::num::NonZeroI32::new(i).unwrap()));
cb(&mut iter)
};
let trampoline = crate::solver::libloading::get_trampoline1(&wrapped_cb);
let layout = std::alloc::Layout::for_value(&wrapped_cb);
let data = Box::leak(Box::new(wrapped_cb)) as *mut _ as *mut std::ffi::c_void;
if layout.size() != 0 {
// Otherwise nothing was leaked.
#learn_cb = Some((data, layout));
}
unsafe {
#krate::ipasir_set_learn(
#ptr,
data,
MAX_LEN,
Some(trampoline),
)
}
} else {
if let Some((ptr, layout)) = #learn_cb .take() {
unsafe { std::alloc::dealloc(ptr as *mut _, layout) };
}
unsafe { #krate::ipasir_set_learn(#ptr, std::ptr::null_mut(), MAX_LEN, None) }

quote! {
impl crate::solver::LearnCallback for #ident {
fn set_learn_callback<F: FnMut(&mut dyn Iterator<Item = crate::Lit>) + 'static>(
&mut self,
cb: Option<F>,
) {
const MAX_LEN: std::ffi::c_int = 512;
if let Some(mut cb) = cb {
let wrapped_cb = move |clause: *const i32| {
let mut iter = crate::solver::libloading::ExplIter(clause)
.map(|i: i32| crate::Lit(std::num::NonZeroI32::new(i).unwrap()));
cb(&mut iter)
};
let trampoline = crate::solver::libloading::get_trampoline1(&wrapped_cb);
#learn_cb = crate::solver::libloading::FFIPointer::new(wrapped_cb);
unsafe {
#krate::ipasir_set_learn(
#ptr,
#learn_cb .get_ptr(),
MAX_LEN,
Some(trampoline),
)
}
} else {
#learn_cb = crate::solver::libloading::FFIPointer::default();
unsafe { #krate::ipasir_set_learn(#ptr, std::ptr::null_mut(), MAX_LEN, None) }
}
}
},
quote! {
if let Some((ptr, layout)) = #learn_cb .take() {
unsafe { std::alloc::dealloc(ptr as *mut _, layout) };
}
},
)
}
}
} else {
(quote!(), quote!())
quote!()
};

let sol_ident = format_ident!("{}Sol", ident);
Expand All @@ -210,8 +183,7 @@ pub fn ipasir_solver_derive(input: TokenStream) -> TokenStream {
#[cfg(feature = "ipasir-up")]
pub(crate) struct #prop_ident {
/// Rust Propagator Storage
prop: *mut c_void,
drop_prop: fn(*mut c_void),
prop: crate::solver::libloading::FFIPointer,
access_prop: fn(*mut c_void) -> *mut dyn std::any::Any,
/// C Wrapper Object
wrapper: *mut std::ffi::c_void,
Expand All @@ -221,24 +193,20 @@ pub fn ipasir_solver_derive(input: TokenStream) -> TokenStream {
impl Drop for #prop_ident {
fn drop(&mut self) {
unsafe { #krate::ipasir_prop_release(self.wrapper) };
(self.drop_prop)(self.prop);
}
}

#[cfg(feature = "ipasir-up")]
impl #prop_ident {
pub(crate) fn new<P: crate::solver::Propagator + 'static>(prop: P, slv: #actions_ident) -> Self {
// Construct wrapping structures
let prop = crate::solver::libloading::IpasirPropStore::new(prop, slv);
let drop_prop = |x: *mut std::ffi::c_void| {
let prop = unsafe { Box::<P>::from_raw(x as *mut P) };
drop(prop);
};
let access_prop = |x: *mut std::ffi::c_void| {
x as *mut P as *mut dyn std::any::Any
let store = crate::solver::libloading::IpasirPropStore::new(prop, slv);
let prop = crate::solver::libloading::FFIPointer::new(store);
let access_prop = |x: *mut std::ffi::c_void| -> *mut dyn std::any::Any {
let store = unsafe{ &mut *(x as *mut crate::solver::libloading::IpasirPropStore<P, #actions_ident>) } ;
(&mut store.prop) as *mut dyn std::any::Any
};
let data = Box::leak(Box::new(prop)) as *mut _ as *mut std::ffi::c_void;
let wrapper = unsafe { #krate::ipasir_prop_init(data as *mut std::ffi::c_void) };
let wrapper = unsafe { #krate::ipasir_prop_init(prop.get_ptr()) };

// Set function pointers for methods
unsafe { #krate::ipasir_prop_set_notify_assignment(wrapper, Some(crate::solver::libloading::ipasir_notify_assignment_cb::<P, #actions_ident>)) };
Expand All @@ -251,7 +219,7 @@ pub fn ipasir_solver_derive(input: TokenStream) -> TokenStream {
unsafe { #krate::ipasir_prop_set_has_external_clause(wrapper, Some(crate::solver::libloading::ipasir_has_external_clause_cb::<P, #actions_ident>)) };
unsafe { #krate::ipasir_prop_set_add_external_clause_lit(wrapper, Some(crate::solver::libloading::ipasir_add_external_clause_lit_cb::<P, #actions_ident>)) };

Self { prop: data, drop_prop, access_prop, wrapper, }
Self { prop, access_prop, wrapper, }
}
}

Expand Down Expand Up @@ -288,14 +256,14 @@ pub fn ipasir_solver_derive(input: TokenStream) -> TokenStream {
#[cfg(feature = "ipasir-up")]
impl crate::solver::PropagatorAccess for #ident {
fn propagator<P: crate::solver::Propagator + 'static>(&self) -> Option<&P> {
#prop_member.as_ref().map(|p| unsafe { &*(p.access_prop)(p.prop) } .downcast_ref()).flatten()
#prop_member.as_ref().map(|p| unsafe { &*(p.access_prop)(p.prop.get_ptr()) } .downcast_ref()).flatten()
}
}

#[cfg(feature = "ipasir-up")]
impl crate::solver::MutPropagatorAccess for #ident {
fn propagator_mut<P: crate::solver::Propagator + 'static>(&mut self) -> Option<&mut P> {
#prop_member.as_ref().map(|p| unsafe { &mut *(p.access_prop)(p.prop) } .downcast_mut()).flatten()
#prop_member.as_ref().map(|p| unsafe { &mut *(p.access_prop)(p.prop.get_ptr()) } .downcast_mut()).flatten()
}
}

Expand Down Expand Up @@ -337,7 +305,7 @@ pub fn ipasir_solver_derive(input: TokenStream) -> TokenStream {
#sol_ident {
ptr: self.ptr,
#[cfg(feature = "ipasir-up")]
prop: #prop_member .as_mut().map(|p| p.prop),
prop: #prop_member .as_mut().map(|p| p.prop.get_ptr()),
#[cfg(feature = "ipasir-up")]
access_prop: #prop_member .as_ref().map(|p| p.access_prop),
}
Expand Down Expand Up @@ -457,8 +425,6 @@ pub fn ipasir_solver_derive(input: TokenStream) -> TokenStream {
quote! {
impl Drop for #ident {
fn drop(&mut self) {
#learn_drop
#term_drop
unsafe { #krate::ipasir_release( #ptr ) }
}
}
Expand Down
15 changes: 7 additions & 8 deletions crates/pindakaas/src/solver/cadical.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#[cfg(feature = "ipasir-up")]
use std::sync::{Arc, Mutex};
use std::{
alloc::Layout,
ffi::{c_void, CString},
fmt,
};
Expand All @@ -10,7 +9,7 @@ use pindakaas_cadical::{ccadical_copy, ccadical_phase, ccadical_unphase};
use pindakaas_derive::IpasirSolver;

use super::VarFactory;
use crate::Lit;
use crate::{solver::libloading::FFIPointer, Lit};

#[derive(IpasirSolver)]
#[ipasir(krate = pindakaas_cadical, assumptions, learn_callback, term_callback, ipasir_up)]
Expand All @@ -24,9 +23,9 @@ pub struct Cadical {
#[cfg(feature = "ipasir-up")]
vars: Arc<Mutex<VarFactory>>,
/// The callback used when a clause is learned.
learn_cb: Option<(*mut c_void, Layout)>,
learn_cb: FFIPointer,
/// The callback used to check whether the solver should terminate.
term_cb: Option<(*mut c_void, Layout)>,
term_cb: FFIPointer,

#[cfg(feature = "ipasir-up")]
/// The external propagator called by the solver
Expand All @@ -41,8 +40,8 @@ impl Default for Cadical {
vars: VarFactory::default(),
#[cfg(feature = "ipasir-up")]
vars: Arc::default(),
learn_cb: None,
term_cb: None,
learn_cb: FFIPointer::default(),
term_cb: FFIPointer::default(),
#[cfg(feature = "ipasir-up")]
prop: None,
}
Expand All @@ -59,8 +58,8 @@ impl Clone for Cadical {
Self {
ptr,
vars,
learn_cb: None,
term_cb: None,
learn_cb: FFIPointer::default(),
term_cb: FFIPointer::default(),
#[cfg(feature = "ipasir-up")]
prop: None,
}
Expand Down
11 changes: 6 additions & 5 deletions crates/pindakaas/src/solver/intel_sat.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::{alloc::Layout, ffi::c_void};
use std::ffi::c_void;

use pindakaas_derive::IpasirSolver;

use super::VarFactory;
use crate::solver::libloading::FFIPointer;

#[derive(Debug, IpasirSolver)]
#[ipasir(krate = pindakaas_intel_sat, assumptions, learn_callback, term_callback)]
Expand All @@ -12,18 +13,18 @@ pub struct IntelSat {
/// The variable factory for this solver.
vars: VarFactory,
/// The callback used when a clause is learned.
learn_cb: Option<(*mut c_void, Layout)>,
learn_cb: FFIPointer,
/// The callback used to check whether the solver should terminate.
term_cb: Option<(*mut c_void, Layout)>,
term_cb: FFIPointer,
}

impl Default for IntelSat {
fn default() -> Self {
Self {
ptr: unsafe { pindakaas_intel_sat::ipasir_init() },
vars: VarFactory::default(),
term_cb: None,
learn_cb: None,
term_cb: FFIPointer::default(),
learn_cb: FFIPointer::default(),
}
}
}
Expand Down
Loading

0 comments on commit c30c0a6

Please sign in to comment.