1#![allow(unreachable_patterns)]
2#![allow(unsafe_op_in_unsafe_fn)]
3
4use std::{
5 collections::HashMap,
6 ffi::CString,
7 sync::Condvar,
8 sync::{Mutex, MutexGuard},
9};
10
11use anyhow::anyhow;
12
13use crate::ffi::{self};
14use crate::{
15 ast::{Constant, Constraint, Model, Var, VarDomain, VarName},
16 error::{MinionError, RuntimeError},
17 scoped_ptr::Scoped,
18};
19
20pub type Callback = fn(solution_set: HashMap<VarName, Constant>) -> bool;
111
112static CALLBACK: Mutex<Option<Callback>> = Mutex::new(None);
117
118static PRINT_VARS: Mutex<Option<Vec<VarName>>> = Mutex::new(None);
120
121static LOCK: (Mutex<bool>, Condvar) = (Mutex::new(false), Condvar::new());
122
123#[unsafe(no_mangle)]
124unsafe extern "C" fn run_callback() -> bool {
125 #[allow(clippy::unwrap_used)]
130 let mut guard: MutexGuard<'_, Option<Vec<VarName>>> = PRINT_VARS.lock().unwrap();
131
132 if guard.is_none() {
133 return true;
134 }
135
136 let print_vars = match &mut *guard {
137 Some(x) => x,
138 None => unreachable!(),
139 };
140
141 if print_vars.is_empty() {
142 return true;
143 }
144
145 let mut solutions: HashMap<VarName, Constant> = HashMap::new();
147
148 for (i, var) in print_vars.iter().enumerate() {
149 let solution_int: i32 = ffi::printMatrix_getValue(i as _);
150 let solution: Constant = Constant::Integer(solution_int);
151 solutions.insert(var.to_string(), solution);
152 }
153
154 #[allow(clippy::unwrap_used)]
155 match *CALLBACK.lock().unwrap() {
156 None => true,
157 Some(func) => func(solutions),
158 }
159}
160
161#[allow(clippy::unwrap_used)]
166pub fn run_minion(model: Model, callback: Callback) -> Result<(), MinionError> {
167 *CALLBACK.lock().unwrap() = Some(callback);
169
170 let (lock, condvar) = &LOCK;
171 let mut _lock_guard = condvar
172 .wait_while(lock.lock().unwrap(), |locked| *locked)
173 .unwrap();
174
175 *_lock_guard = true;
176
177 unsafe {
178 let search_opts = ffi::searchOptions_new();
180 let search_method = ffi::searchMethod_new();
181 let search_instance = ffi::instance_new();
182
183 convert_model_to_raw(search_instance, &model)?;
184
185 let res = ffi::runMinion(
186 search_opts,
187 search_method,
188 search_instance,
189 Some(run_callback),
190 );
191
192 ffi::searchMethod_free(search_method);
193 ffi::searchOptions_free(search_opts);
194 ffi::instance_free(search_instance);
195
196 *_lock_guard = false;
197 std::mem::drop(_lock_guard);
198
199 condvar.notify_one();
200
201 match res {
202 0 => Ok(()),
203 x => Err(MinionError::from(RuntimeError::from(x))),
204 }
205 }
206}
207
208unsafe fn convert_model_to_raw(
209 instance: *mut ffi::ProbSpec_CSPInstance,
210 model: &Model,
211) -> Result<(), MinionError> {
212 let search_vars = Scoped::new(ffi::vec_var_new(), |x| ffi::vec_var_free(x as _));
226
227 #[allow(clippy::unwrap_used)]
229 let mut print_vars_guard = PRINT_VARS.lock().unwrap();
230 *print_vars_guard = Some(vec![]);
231
232 for var_name in model.named_variables.get_variable_order() {
234 let c_str = CString::new(var_name.clone()).map_err(|_| {
235 anyhow!(
236 "Variable name {:?} contains a null character.",
237 var_name.clone()
238 )
239 })?;
240
241 let vartype = model
242 .named_variables
243 .get_vartype(var_name.clone())
244 .ok_or(anyhow!("Could not get var type for {:?}", var_name.clone()))?;
245
246 let (vartype_raw, domain_low, domain_high) = match vartype {
247 VarDomain::Bound(a, b) => Ok((ffi::VariableType_VAR_BOUND, a, b)),
248 VarDomain::Bool => Ok((ffi::VariableType_VAR_BOOL, 0, 1)), x => Err(MinionError::NotImplemented(format!("{x:?}"))),
250 }?;
251
252 ffi::newVar_ffi(
253 instance,
254 c_str.as_ptr() as _,
255 vartype_raw,
256 domain_low,
257 domain_high,
258 );
259
260 let var = ffi::getVarByName(instance, c_str.as_ptr() as _);
261
262 ffi::printMatrix_addVar(instance, var);
263
264 #[allow(clippy::unwrap_used)]
268 (*print_vars_guard).as_mut().unwrap().push(var_name.clone());
269 }
270
271 for search_var_name in model.named_variables.get_search_variable_order() {
273 let c_str = CString::new(search_var_name.clone()).map_err(|_| {
274 anyhow!(
275 "Variable name {:?} contains a null character.",
276 search_var_name.clone()
277 )
278 })?;
279 let var = ffi::getVarByName(instance, c_str.as_ptr() as _);
280 ffi::vec_var_push_back(search_vars.ptr, var);
281 }
282
283 let search_order = Scoped::new(
284 ffi::searchOrder_new(search_vars.ptr, ffi::VarOrderEnum_ORDER_STATIC, false),
285 |x| ffi::searchOrder_free(x as _),
286 );
287
288 ffi::instance_addSearchOrder(instance, search_order.ptr);
289
290 for constraint in &model.constraints {
295 let constraint_type = get_constraint_type(constraint)?;
300 let raw_constraint = Scoped::new(ffi::constraint_new(constraint_type), |x| {
301 ffi::constraint_free(x as _)
302 });
303
304 constraint_add_args(instance, raw_constraint.ptr, constraint)?;
305 ffi::instance_addConstraint(instance, raw_constraint.ptr);
306 }
307
308 Ok(())
309}
310
311unsafe fn get_constraint_type(constraint: &Constraint) -> Result<u32, MinionError> {
312 match constraint {
313 Constraint::SumGeq(_, _) => Ok(ffi::ConstraintType_CT_GEQSUM),
314 Constraint::SumLeq(_, _) => Ok(ffi::ConstraintType_CT_LEQSUM),
315 Constraint::Ineq(_, _, _) => Ok(ffi::ConstraintType_CT_INEQ),
316 Constraint::Eq(_, _) => Ok(ffi::ConstraintType_CT_EQ),
317 Constraint::Difference(_, _) => Ok(ffi::ConstraintType_CT_DIFFERENCE),
318 Constraint::Div(_, _) => Ok(ffi::ConstraintType_CT_DIV),
319 Constraint::DivUndefZero(_, _) => Ok(ffi::ConstraintType_CT_DIV_UNDEFZERO),
320 Constraint::Modulo(_, _) => Ok(ffi::ConstraintType_CT_MODULO),
321 Constraint::ModuloUndefZero(_, _) => Ok(ffi::ConstraintType_CT_MODULO_UNDEFZERO),
322 Constraint::Pow(_, _) => Ok(ffi::ConstraintType_CT_POW),
323 Constraint::Product(_, _) => Ok(ffi::ConstraintType_CT_PRODUCT2),
324 Constraint::WeightedSumGeq(_, _, _) => Ok(ffi::ConstraintType_CT_WEIGHTGEQSUM),
325 Constraint::WeightedSumLeq(_, _, _) => Ok(ffi::ConstraintType_CT_WEIGHTLEQSUM),
326 Constraint::CheckAssign(_) => Ok(ffi::ConstraintType_CT_CHECK_ASSIGN),
327 Constraint::CheckGsa(_) => Ok(ffi::ConstraintType_CT_CHECK_GSA),
328 Constraint::ForwardChecking(_) => Ok(ffi::ConstraintType_CT_FORWARD_CHECKING),
329 Constraint::Reify(_, _) => Ok(ffi::ConstraintType_CT_REIFY),
330 Constraint::ReifyImply(_, _) => Ok(ffi::ConstraintType_CT_REIFYIMPLY),
331 Constraint::ReifyImplyQuick(_, _) => Ok(ffi::ConstraintType_CT_REIFYIMPLY_QUICK),
332 Constraint::WatchedAnd(_) => Ok(ffi::ConstraintType_CT_WATCHED_NEW_AND),
333 Constraint::WatchedOr(_) => Ok(ffi::ConstraintType_CT_WATCHED_NEW_OR),
334 Constraint::GacAllDiff(_) => Ok(ffi::ConstraintType_CT_GACALLDIFF),
335 Constraint::AllDiff(_) => Ok(ffi::ConstraintType_CT_ALLDIFF),
336 Constraint::AllDiffMatrix(_, _) => Ok(ffi::ConstraintType_CT_ALLDIFFMATRIX),
337 Constraint::WatchSumGeq(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_GEQSUM),
338 Constraint::WatchSumLeq(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_LEQSUM),
339 Constraint::OccurrenceGeq(_, _, _) => Ok(ffi::ConstraintType_CT_GEQ_OCCURRENCE),
340 Constraint::OccurrenceLeq(_, _, _) => Ok(ffi::ConstraintType_CT_LEQ_OCCURRENCE),
341 Constraint::Occurrence(_, _, _) => Ok(ffi::ConstraintType_CT_OCCURRENCE),
342 Constraint::LitSumGeq(_, _, _) => Ok(ffi::ConstraintType_CT_WATCHED_LITSUM),
343 Constraint::Gcc(_, _, _) => Ok(ffi::ConstraintType_CT_GCC),
344 Constraint::GccWeak(_, _, _) => Ok(ffi::ConstraintType_CT_GCCWEAK),
345 Constraint::LexLeqRv(_, _) => Ok(ffi::ConstraintType_CT_GACLEXLEQ),
346 Constraint::LexLeq(_, _) => Ok(ffi::ConstraintType_CT_LEXLEQ),
347 Constraint::LexLess(_, _) => Ok(ffi::ConstraintType_CT_LEXLESS),
348 Constraint::LexLeqQuick(_, _) => Ok(ffi::ConstraintType_CT_QUICK_LEXLEQ),
349 Constraint::LexLessQuick(_, _) => Ok(ffi::ConstraintType_CT_QUICK_LEXLEQ),
350 Constraint::WatchVecNeq(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_VECNEQ),
351 Constraint::WatchVecExistsLess(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_VEC_OR_LESS),
352 Constraint::Hamming(_, _, _) => Ok(ffi::ConstraintType_CT_WATCHED_HAMMING),
353 Constraint::NotHamming(_, _, _) => Ok(ffi::ConstraintType_CT_WATCHED_NOT_HAMMING),
354 Constraint::FrameUpdate(_, _, _, _, _) => Ok(ffi::ConstraintType_CT_FRAMEUPDATE),
355 Constraint::NegativeTable(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_NEGATIVE_TABLE),
356 Constraint::Table(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_TABLE),
357 Constraint::GacSchema(_, _) => Ok(ffi::ConstraintType_CT_GACSCHEMA),
358 Constraint::LightTable(_, _) => Ok(ffi::ConstraintType_CT_LIGHTTABLE),
359 Constraint::Mddc(_, _) => Ok(ffi::ConstraintType_CT_MDDC),
360 Constraint::NegativeMddc(_, _) => Ok(ffi::ConstraintType_CT_NEGATIVEMDDC),
361 Constraint::Str2Plus(_, _) => Ok(ffi::ConstraintType_CT_STR),
362 Constraint::Max(_, _) => Ok(ffi::ConstraintType_CT_MAX),
363 Constraint::Min(_, _) => Ok(ffi::ConstraintType_CT_MIN),
364 Constraint::NvalueGeq(_, _) => Ok(ffi::ConstraintType_CT_GEQNVALUE),
365 Constraint::NvalueLeq(_, _) => Ok(ffi::ConstraintType_CT_LEQNVALUE),
366 Constraint::Element(_, _, _) => Ok(ffi::ConstraintType_CT_ELEMENT),
367 Constraint::ElementOne(_, _, _) => Ok(ffi::ConstraintType_CT_ELEMENT_ONE),
368 Constraint::ElementUndefZero(_, _, _) => Ok(ffi::ConstraintType_CT_ELEMENT_UNDEFZERO),
369 Constraint::WatchElement(_, _, _) => Ok(ffi::ConstraintType_CT_WATCHED_ELEMENT),
370 Constraint::WatchElementOne(_, _, _) => Ok(ffi::ConstraintType_CT_WATCHED_ELEMENT_ONE),
371 Constraint::WatchElementOneUndefZero(_, _, _) => {
372 Ok(ffi::ConstraintType_CT_WATCHED_ELEMENT_ONE_UNDEFZERO)
373 }
374 Constraint::WatchElementUndefZero(_, _, _) => {
375 Ok(ffi::ConstraintType_CT_WATCHED_ELEMENT_UNDEFZERO)
376 }
377 Constraint::WLiteral(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_LIT),
378 Constraint::WNotLiteral(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_NOTLIT),
379 Constraint::WInIntervalSet(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_ININTERVALSET),
380 Constraint::WInRange(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_INRANGE),
381 Constraint::WInset(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_INSET),
382 Constraint::WNotInRange(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_NOT_INRANGE),
383 Constraint::WNotInset(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_NOT_INSET),
384 Constraint::Abs(_, _) => Ok(ffi::ConstraintType_CT_ABS),
385 Constraint::DisEq(_, _) => Ok(ffi::ConstraintType_CT_DISEQ),
386 Constraint::MinusEq(_, _) => Ok(ffi::ConstraintType_CT_MINUSEQ),
387 Constraint::GacEq(_, _) => Ok(ffi::ConstraintType_CT_GACEQ),
388 Constraint::WatchLess(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_LESS),
389 Constraint::WatchNeq(_, _) => Ok(ffi::ConstraintType_CT_WATCHED_NEQ),
390 Constraint::True => Ok(ffi::ConstraintType_CT_TRUE),
391 Constraint::False => Ok(ffi::ConstraintType_CT_FALSE),
392
393 #[allow(unreachable_patterns)]
394 x => Err(MinionError::NotImplemented(format!(
395 "Constraint not implemented {x:?}",
396 ))),
397 }
398}
399
400unsafe fn constraint_add_args(
401 i: *mut ffi::ProbSpec_CSPInstance,
402 r_constr: *mut ffi::ProbSpec_ConstraintBlob,
403 constr: &Constraint,
404) -> Result<(), MinionError> {
405 match constr {
406 Constraint::SumGeq(lhs_vars, rhs_var) => {
407 read_list(i, r_constr, lhs_vars)?;
408 read_var(i, r_constr, rhs_var)?;
409 Ok(())
410 }
411 Constraint::SumLeq(lhs_vars, rhs_var) => {
412 read_list(i, r_constr, lhs_vars)?;
413 read_var(i, r_constr, rhs_var)?;
414 Ok(())
415 }
416 Constraint::Ineq(var1, var2, c) => {
417 read_var(i, r_constr, var1)?;
418 read_var(i, r_constr, var2)?;
419 read_constant(r_constr, c)?;
420 Ok(())
421 }
422 Constraint::Eq(var1, var2) => {
423 read_var(i, r_constr, var1)?;
424 read_var(i, r_constr, var2)?;
425 Ok(())
426 }
427 Constraint::Difference((a, b), c) => {
428 read_2_vars(i, r_constr, a, b)?;
429 read_var(i, r_constr, c)?;
430 Ok(())
431 }
432 Constraint::Div((a, b), c) => {
433 read_2_vars(i, r_constr, a, b)?;
434 read_var(i, r_constr, c)?;
435 Ok(())
436 }
437 Constraint::DivUndefZero((a, b), c) => {
438 read_2_vars(i, r_constr, a, b)?;
439 read_var(i, r_constr, c)?;
440 Ok(())
441 }
442 Constraint::Modulo((a, b), c) => {
443 read_2_vars(i, r_constr, a, b)?;
444 read_var(i, r_constr, c)?;
445 Ok(())
446 }
447 Constraint::ModuloUndefZero((a, b), c) => {
448 read_2_vars(i, r_constr, a, b)?;
449 read_var(i, r_constr, c)?;
450 Ok(())
451 }
452 Constraint::Pow((a, b), c) => {
453 read_2_vars(i, r_constr, a, b)?;
454 read_var(i, r_constr, c)?;
455 Ok(())
456 }
457 Constraint::Product((a, b), c) => {
458 read_2_vars(i, r_constr, a, b)?;
459 read_var(i, r_constr, c)?;
460 Ok(())
461 }
462 Constraint::WeightedSumGeq(a, b, c) => {
463 read_constant_list(r_constr, a)?;
464 read_list(i, r_constr, b)?;
465 read_var(i, r_constr, c)?;
466 Ok(())
467 }
468 Constraint::WeightedSumLeq(a, b, c) => {
469 read_constant_list(r_constr, a)?;
470 read_list(i, r_constr, b)?;
471 read_var(i, r_constr, c)?;
472 Ok(())
473 }
474 Constraint::CheckAssign(a) => {
475 read_constraint(i, r_constr, (**a).clone())?;
476 Ok(())
477 }
478 Constraint::CheckGsa(a) => {
479 read_constraint(i, r_constr, (**a).clone())?;
480 Ok(())
481 }
482 Constraint::ForwardChecking(a) => {
483 read_constraint(i, r_constr, (**a).clone())?;
484 Ok(())
485 }
486 Constraint::Reify(a, b) => {
487 read_constraint(i, r_constr, (**a).clone())?;
488 read_var(i, r_constr, b)?;
489 Ok(())
490 }
491 Constraint::ReifyImply(a, b) => {
492 read_constraint(i, r_constr, (**a).clone())?;
493 read_var(i, r_constr, b)?;
494 Ok(())
495 }
496 Constraint::ReifyImplyQuick(a, b) => {
497 read_constraint(i, r_constr, (**a).clone())?;
498 read_var(i, r_constr, b)?;
499 Ok(())
500 }
501 Constraint::WatchedAnd(a) => {
502 read_constraint_list(i, r_constr, a)?;
503 Ok(())
504 }
505 Constraint::WatchedOr(a) => {
506 read_constraint_list(i, r_constr, a)?;
507 Ok(())
508 }
509 Constraint::GacAllDiff(a) => {
510 read_list(i, r_constr, a)?;
511 Ok(())
512 }
513 Constraint::AllDiff(a) => {
514 read_list(i, r_constr, a)?;
515 Ok(())
516 }
517 Constraint::AllDiffMatrix(a, b) => {
518 read_list(i, r_constr, a)?;
519 read_constant(r_constr, b)?;
520 Ok(())
521 }
522 Constraint::WatchSumGeq(a, b) => {
523 read_list(i, r_constr, a)?;
524 read_constant(r_constr, b)?;
525 Ok(())
526 }
527 Constraint::WatchSumLeq(a, b) => {
528 read_list(i, r_constr, a)?;
529 read_constant(r_constr, b)?;
530 Ok(())
531 }
532 Constraint::OccurrenceGeq(a, b, c) => {
533 read_list(i, r_constr, a)?;
534 read_constant(r_constr, b)?;
535 read_constant(r_constr, c)?;
536 Ok(())
537 }
538 Constraint::OccurrenceLeq(a, b, c) => {
539 read_list(i, r_constr, a)?;
540 read_constant(r_constr, b)?;
541 read_constant(r_constr, c)?;
542 Ok(())
543 }
544 Constraint::Occurrence(a, b, c) => {
545 read_list(i, r_constr, a)?;
546 read_constant(r_constr, b)?;
547 read_var(i, r_constr, c)?;
548 Ok(())
549 }
550 Constraint::LexLess(a, b) => {
551 read_list(i, r_constr, a)?;
552 read_list(i, r_constr, b)?;
553 Ok(())
554 }
555 Constraint::LexLeq(a, b) => {
556 read_list(i, r_constr, a)?;
557 read_list(i, r_constr, b)?;
558 Ok(())
559 }
560 Constraint::ElementOne(vec, j, e) => {
587 read_list(i, r_constr, vec)?;
588 read_var(i, r_constr, j)?;
589 read_var(i, r_constr, e)?;
590 Ok(())
591 }
592 Constraint::WLiteral(a, b) => {
595 read_var(i, r_constr, a)?;
596 read_constant(r_constr, b)?;
597 Ok(())
598 }
599 Constraint::WInIntervalSet(var, consts) => {
601 read_var(i, r_constr, var)?;
602 read_constant_list(r_constr, consts)?;
603 Ok(())
604 }
605 Constraint::WInset(a, b) => {
607 read_var(i, r_constr, a)?;
608 read_constant_list(r_constr, b)?;
609 Ok(())
610 }
611 Constraint::Abs(a, b) => {
614 read_var(i, r_constr, a)?;
615 read_var(i, r_constr, b)?;
616 Ok(())
617 }
618 Constraint::DisEq(a, b) => {
619 read_var(i, r_constr, a)?;
620 read_var(i, r_constr, b)?;
621 Ok(())
622 }
623 Constraint::MinusEq(a, b) => {
624 read_var(i, r_constr, a)?;
625 read_var(i, r_constr, b)?;
626 Ok(())
627 }
628 Constraint::WatchNeq(a, b) => {
632 read_var(i, r_constr, a)?;
633 read_var(i, r_constr, b)?;
634 Ok(())
635 }
636
637 Constraint::True => Ok(()),
638 Constraint::False => Ok(()),
639 #[allow(unreachable_patterns)]
640 x => Err(MinionError::NotImplemented(format!("{x:?}"))),
641 }
642}
643
644unsafe fn read_list(
647 instance: *mut ffi::ProbSpec_CSPInstance,
648 raw_constraint: *mut ffi::ProbSpec_ConstraintBlob,
649 vars: &Vec<Var>,
650) -> Result<(), MinionError> {
651 let raw_vars = Scoped::new(ffi::vec_var_new(), |x| ffi::vec_var_free(x as _));
652 for var in vars {
653 let raw_var = match var {
654 Var::NameRef(name) => {
655 let c_str = CString::new(name.clone()).map_err(|_| {
656 anyhow!(
657 "Variable name {:?} contains a null character.",
658 name.clone()
659 )
660 })?;
661 ffi::getVarByName(instance, c_str.as_ptr() as _)
662 }
663 Var::ConstantAsVar(n) => ffi::constantAsVar(*n),
664 };
665
666 ffi::vec_var_push_back(raw_vars.ptr, raw_var);
667 }
668
669 ffi::constraint_addList(raw_constraint, raw_vars.ptr);
670
671 Ok(())
672}
673
674unsafe fn read_var(
675 instance: *mut ffi::ProbSpec_CSPInstance,
676 raw_constraint: *mut ffi::ProbSpec_ConstraintBlob,
677 var: &Var,
678) -> Result<(), MinionError> {
679 let raw_vars = Scoped::new(ffi::vec_var_new(), |x| ffi::vec_var_free(x as _));
680 let raw_var = match var {
681 Var::NameRef(name) => {
682 let c_str = CString::new(name.clone()).map_err(|_| {
683 anyhow!(
684 "Variable name {:?} contains a null character.",
685 name.clone()
686 )
687 })?;
688 ffi::getVarByName(instance, c_str.as_ptr() as _)
689 }
690 Var::ConstantAsVar(n) => ffi::constantAsVar(*n),
691 };
692
693 ffi::vec_var_push_back(raw_vars.ptr, raw_var);
694 ffi::constraint_addList(raw_constraint, raw_vars.ptr);
695
696 Ok(())
697}
698
699unsafe fn read_2_vars(
700 instance: *mut ffi::ProbSpec_CSPInstance,
701 raw_constraint: *mut ffi::ProbSpec_ConstraintBlob,
702 var1: &Var,
703 var2: &Var,
704) -> Result<(), MinionError> {
705 let mut raw_var = match var1 {
706 Var::NameRef(name) => {
707 let c_str = CString::new(name.clone()).map_err(|_| {
708 anyhow!(
709 "Variable name {:?} contains a null character.",
710 name.clone()
711 )
712 })?;
713 ffi::getVarByName(instance, c_str.as_ptr() as _)
714 }
715 Var::ConstantAsVar(n) => ffi::constantAsVar(*n),
716 };
717 let mut raw_var2 = match var2 {
718 Var::NameRef(name) => {
719 let c_str = CString::new(name.clone()).map_err(|_| {
720 anyhow!(
721 "Variable name {:?} contains a null character.",
722 name.clone()
723 )
724 })?;
725 ffi::getVarByName(instance, c_str.as_ptr() as _)
726 }
727 Var::ConstantAsVar(n) => ffi::constantAsVar(*n),
728 };
729 ffi::constraint_addTwoVars(raw_constraint, &mut raw_var, &mut raw_var2);
733 Ok(())
734}
735
736unsafe fn read_constant(
737 raw_constraint: *mut ffi::ProbSpec_ConstraintBlob,
738 constant: &Constant,
739) -> Result<(), MinionError> {
740 let val: i32 = match constant {
741 Constant::Integer(n) => Ok(*n),
742 Constant::Bool(true) => Ok(1),
743 Constant::Bool(false) => Ok(0),
744 x => Err(MinionError::NotImplemented(format!("{x:?}"))),
745 }?;
746
747 ffi::constraint_addConstant(raw_constraint, val);
748
749 Ok(())
750}
751
752unsafe fn read_constant_list(
753 raw_constraint: *mut ffi::ProbSpec_ConstraintBlob,
754 constants: &[Constant],
755) -> Result<(), MinionError> {
756 let raw_consts = Scoped::new(ffi::vec_int_new(), |x| ffi::vec_var_free(x as _));
757
758 for constant in constants.iter() {
759 let val = match constant {
760 Constant::Integer(n) => Ok(*n),
761 Constant::Bool(true) => Ok(1),
762 Constant::Bool(false) => Ok(0),
763 #[allow(unreachable_patterns)] x => Err(MinionError::NotImplemented(format!("{x:?}"))),
765 }?;
766
767 ffi::vec_int_push_back(raw_consts.ptr, val);
768 }
769
770 ffi::constraint_addConstantList(raw_constraint, raw_consts.ptr);
771 Ok(())
772}
773
774unsafe fn read_constraint(
778 instance: *mut ffi::ProbSpec_CSPInstance,
779 raw_constraint: *mut ffi::ProbSpec_ConstraintBlob,
780 inner_constraint: Constraint,
781) -> Result<(), MinionError> {
782 let constraint_type = get_constraint_type(&inner_constraint)?;
783 let raw_inner_constraint = Scoped::new(ffi::constraint_new(constraint_type), |x| {
784 ffi::constraint_free(x as _)
785 });
786
787 constraint_add_args(instance, raw_inner_constraint.ptr, &inner_constraint)?;
788
789 ffi::constraint_addConstraint(raw_constraint, raw_inner_constraint.ptr);
790 Ok(())
791}
792
793unsafe fn read_constraint_list(
794 instance: *mut ffi::ProbSpec_CSPInstance,
795 raw_constraint: *mut ffi::ProbSpec_ConstraintBlob,
796 inner_constraints: &[Constraint],
797) -> Result<(), MinionError> {
798 let raw_inners = Scoped::new(ffi::vec_constraints_new(), |x| {
799 ffi::vec_constraints_free(x as _)
800 });
801 for inner_constraint in inner_constraints.iter() {
802 let constraint_type = get_constraint_type(inner_constraint)?;
803 let raw_inner_constraint = Scoped::new(ffi::constraint_new(constraint_type), |x| {
804 ffi::constraint_free(x as _)
805 });
806
807 constraint_add_args(instance, raw_inner_constraint.ptr, inner_constraint)?;
808 ffi::vec_constraints_push_back(raw_inners.ptr, raw_inner_constraint.ptr);
809 }
810
811 ffi::constraint_addConstraintList(raw_constraint, raw_inners.ptr);
812 Ok(())
813}