-
Notifications
You must be signed in to change notification settings - Fork 9
/
lib.rs
6029 lines (5754 loc) · 216 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#![doc(html_root_url = "https://docs.rs/clingo/0.6.0")]
//! This crate provides bindings to the [clingo](https://github.com/potassco/clingo) library version 5.4.0.
//!
//! ## Requirements
//!
//! - a c++14 conforming compiler
//! - *at least* [gcc](https://gcc.gnu.org/) version 4.9
//! - [clang](http://clang.llvm.org/) version 3.1 (using either libstdc++
//! provided by gcc 4.9 or libc++)
//!
//!
//! ## Using `derive` macro
//!
//! The crate provides a derive macro to help easing the use of rust data types as facts.
//!
//!
//! In your `Cargo.toml` add:
//! ```toml
//! [dependencies]
//! clingo = { version = "0.6", features = ["derive"] }
//! ```
//!
//! In your source write:
//! ```ignore
//! use clingo::ToSymbol;
//! use clingo::ClingoError;
//! use clingo::FactBase;
//!
//! #[derive(ToSymbol)]
//! struct MyPoint {
//! x: i32,
//! y: i32,
//! }
//!
//! let p = MyPoint{ x:4, y:2 };
//! let fb = FactBase::new();
//! fb.insert(p);
//! ```
//!
//! The macro performs a conversion to snake case. This means the corresponing fact for `MyPoint{x:4,y:2}` is `my_point(4,2)`.
//!
//!
//! ## Using `dynamic_linking`
//!
//! The crate defines a [Cargo feature] that allows to use the clingo library via dynamic linking.
//!
//! [Cargo feature]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
//!
//! With dynamic linking enabled the clingo library is not build for static linking but it is assumed that a
//! clingo dynamic library is installed on the system.
//!
//! The recommended way to use the optional dynamic linking support is as
//! follows.
//!
//! ```toml
//! [dependencies]
//! clingo = { version = "0.6.0", features = ["derive", "dynamic_linking"] }
//! ```
//!
#![allow(non_upper_case_globals)]
#![allow(clippy::try_err)]
use bitflags::bitflags;
use clingo_sys::*;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::ffi::CStr;
use std::ffi::CString;
use std::ffi::NulError;
use std::hash::{Hash, Hasher};
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::ptr::NonNull;
use std::str::Utf8Error;
use thiserror::Error;
/// Functions and data structures to work with program ASTs.
pub mod ast;
/// ClingoError in the rust wrapper, like null pointers or failed matches of C enums.
///
/// Includes internal error from the clingo library.
///
/// **Note:** Errors can only be recovered from if explicitly mentioned; most
/// functions do not provide strong exception guarantees. This means that in
/// case of errors associated objects cannot be used further.
#[derive(Error, Debug)]
pub enum ClingoError {
#[error("NulError: ")]
NulError(#[from] NulError),
#[error("Utf8Error: ")]
Utf8Error(#[from] Utf8Error),
#[error("FFIError: {msg}")]
FFIError { msg: &'static str },
#[error("InternalError: {msg}, code: {code:?}, last: {last}")]
InternalError {
msg: &'static str,
code: ErrorCode,
last: &'static str,
},
#[error("ExternalError: ")]
ExternalError(#[from] ExternalError),
}
impl ClingoError {
fn new_internal(msg: &'static str) -> ClingoError {
ClingoError::InternalError {
msg,
code: error_code(),
last: error_message(),
}
}
}
#[derive(Error, Debug)]
#[error("ExternalError: {msg}")]
pub struct ExternalError {
pub msg: &'static str,
}
/// Enumeration of clingo error types
/// See: set_error()
#[derive(Debug, Copy, Clone)]
pub enum ErrorType {
/// Successful API calls
Success = clingo_error_clingo_error_success as isize,
/// Errors only detectable at runtime like invalid input
Runtime = clingo_error_clingo_error_runtime as isize,
/// Wrong usage of the clingo API
Logic = clingo_error_clingo_error_logic as isize,
/// Memory could not be allocated
BadAlloc = clingo_error_clingo_error_bad_alloc as isize,
/// Errors unrelated to clingo
Unknown = clingo_error_clingo_error_unknown as isize,
}
/// Enumeration of clingo error codes for [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError).
#[derive(Debug, Copy, Clone)]
pub enum ErrorCode {
/// Successful API calls
Success,
/// Errors only detectable at runtime like invalid input
Runtime,
/// Wrong usage of the clingo API
Logic,
/// Memory could not be allocated
BadAlloc,
/// Errors unrelated to clingo
Unknown,
/// FFI failed to match clingo_error
FFIError,
}
impl From<i32> for ErrorCode {
fn from(error: i32) -> Self {
match error as u32 {
clingo_error_clingo_error_success => ErrorCode::Success,
clingo_error_clingo_error_runtime => ErrorCode::Runtime,
clingo_error_clingo_error_logic => ErrorCode::Logic,
clingo_error_clingo_error_bad_alloc => ErrorCode::BadAlloc,
clingo_error_clingo_error_unknown => ErrorCode::Unknown,
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_error {}",
file!(),
line!(),
column!(),
x
);
ErrorCode::FFIError
}
}
}
}
/// Get the last error code set by a clingo API call.
///
/// **Note:** Each thread has its own local error code.
fn error_code() -> ErrorCode {
ErrorCode::from(unsafe { clingo_error_code() })
}
/// Get the last error message set if an API call fails.
///
/// **Note:** Each thread has its own local error message.
fn error_message() -> &'static str {
let char_ptr: *const c_char = unsafe { clingo_error_message() };
if char_ptr.is_null() {
"Ooops, original error message is null."
} else {
let c_str = unsafe { CStr::from_ptr(char_ptr) };
c_str
.to_str()
.unwrap_or("Ooops, original error message was no valid utf8 string.")
}
}
/// Set an error code and message in the active thread.
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `message` contains a nul byte
pub fn set_error(code: ErrorType, message: &str) -> Result<(), NulError> {
let message = CString::new(message)?;
unsafe { clingo_set_error(code as clingo_error_t, message.as_ptr()) }
Ok(())
}
fn set_internal_error(code: ErrorType, message: &'static str) {
// unwrap won't panic, because the function is only used internally on valid strings
let message = CString::new(message).unwrap();
unsafe { clingo_set_error(code as clingo_error_t, message.as_ptr()) }
}
/// Represents three-valued truth values.
#[derive(Debug, Copy, Clone)]
pub enum TruthValue {
/// No truth value
Free = clingo_truth_value_clingo_truth_value_free as isize,
/// True
True = clingo_truth_value_clingo_truth_value_true as isize,
/// False
False = clingo_truth_value_clingo_truth_value_false as isize,
}
impl TruthValue {
fn try_from(code: i32) -> Result<TruthValue, ClingoError> {
match code as u32 {
clingo_truth_value_clingo_truth_value_false => Ok(TruthValue::False),
clingo_truth_value_clingo_truth_value_true => Ok(TruthValue::True),
clingo_truth_value_clingo_truth_value_free => Ok(TruthValue::Free),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_truth_value {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_truth_value.",
})
}
}
}
}
/// Enumeration of clause types determining the lifetime of a clause.
///
/// Clauses in the solver are either cleaned up based on a configurable deletion policy or at the end of a solving step.
/// The values of this enumeration determine if a clause is subject to one of the above deletion strategies.
#[derive(Debug, Copy, Clone)]
pub enum ClauseType {
/// The clause is subject to the solvers deletion policy
Learnt = clingo_clause_type_clingo_clause_type_learnt as isize,
/// The clause is not subject to the solvers deletion policy
Static = clingo_clause_type_clingo_clause_type_static as isize,
/// Like `Learnt` but the clause is deleted after a solving step
Volatile = clingo_clause_type_clingo_clause_type_volatile as isize,
/// Like `Static` but the clause is deleted after a solving step
VolatileStatic = clingo_clause_type_clingo_clause_type_volatile_static as isize,
}
/// Enumeration of solve events.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum SolveEventType {
/// Issued if a model is found.
Model = clingo_solve_event_type_clingo_solve_event_type_model as isize,
/// Issued when the statistics can be updated.
Statistics = clingo_solve_event_type_clingo_solve_event_type_statistics as isize,
/// Issued if the search has completed.
Finish = clingo_solve_event_type_clingo_solve_event_type_finish as isize,
}
impl SolveEventType {
fn try_from(code: u32) -> Result<SolveEventType, ClingoError> {
match code {
clingo_solve_event_type_clingo_solve_event_type_model => Ok(SolveEventType::Model),
clingo_solve_event_type_clingo_solve_event_type_statistics => {
Ok(SolveEventType::Statistics)
}
clingo_solve_event_type_clingo_solve_event_type_finish => Ok(SolveEventType::Finish),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_solve_event_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_solve_event_type.",
})
}
}
}
}
/// Enumeration for entries of the statistics.
#[derive(Debug, Copy, Clone)]
pub enum StatisticsType {
/// The entry is invalid (has neither of the types below)
Empty = clingo_statistics_type_clingo_statistics_type_empty as isize,
/// The entry is a (double) value
Value = clingo_statistics_type_clingo_statistics_type_value as isize,
/// The entry is an array
Array = clingo_statistics_type_clingo_statistics_type_array as isize,
/// The entry is a map
Map = clingo_statistics_type_clingo_statistics_type_map as isize,
}
impl StatisticsType {
fn try_from(code: i32) -> Result<StatisticsType, ClingoError> {
match code as u32 {
clingo_statistics_type_clingo_statistics_type_empty => Ok(StatisticsType::Empty),
clingo_statistics_type_clingo_statistics_type_value => Ok(StatisticsType::Value),
clingo_statistics_type_clingo_statistics_type_array => Ok(StatisticsType::Array),
clingo_statistics_type_clingo_statistics_type_map => Ok(StatisticsType::Map),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_statistics_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_statistics_type.",
})
}
}
}
}
/// Enumeration of available symbol types.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum SymbolType {
/// The `#inf` symbol
Infimum = clingo_symbol_type_clingo_symbol_type_infimum as isize,
/// A numeric symbol, e.g., `1`
Number = clingo_symbol_type_clingo_symbol_type_number as isize,
/// A string symbol, e.g., `"a"`
String = clingo_symbol_type_clingo_symbol_type_string as isize,
/// A numeric symbol, e.g., `c`, `(1, "a")`, or `f(1,"a")`
Function = clingo_symbol_type_clingo_symbol_type_function as isize,
/// The `#sup` symbol
Supremum = clingo_symbol_type_clingo_symbol_type_supremum as isize,
}
impl SymbolType {
fn try_from(code: i32) -> Result<SymbolType, ClingoError> {
match code as u32 {
clingo_symbol_type_clingo_symbol_type_infimum => Ok(SymbolType::Infimum),
clingo_symbol_type_clingo_symbol_type_number => Ok(SymbolType::Number),
clingo_symbol_type_clingo_symbol_type_string => Ok(SymbolType::String),
clingo_symbol_type_clingo_symbol_type_function => Ok(SymbolType::Function),
clingo_symbol_type_clingo_symbol_type_supremum => Ok(SymbolType::Supremum),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_symbol_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_symbol_type.",
})
}
}
}
}
/// Enumeration of warning codes.
#[derive(Debug, Copy, Clone)]
pub enum Warning {
/// Undefined arithmetic operation or weight of aggregate
OperationUndefined = clingo_warning_clingo_warning_operation_undefined as isize,
/// To report multiple errors; a corresponding runtime error is raised later
RuntimeError = clingo_warning_clingo_warning_runtime_error as isize,
/// An undefined atom in program
AtomUndefined = clingo_warning_clingo_warning_atom_undefined as isize,
/// The Same file included multiple times
FileIncluded = clingo_warning_clingo_warning_file_included as isize,
/// CSP variable with unbounded domain
VariableUnbound = clingo_warning_clingo_warning_variable_unbounded as isize,
/// A global variable in tuple of aggregate element
GlobalVariable = clingo_warning_clingo_warning_global_variable as isize,
/// Other kinds of warnings
Other = clingo_warning_clingo_warning_other as isize,
}
impl Warning {
fn try_from(code: i32) -> Result<Warning, ClingoError> {
match code as u32 {
clingo_warning_clingo_warning_atom_undefined => Ok(Warning::AtomUndefined),
clingo_warning_clingo_warning_file_included => Ok(Warning::FileIncluded),
clingo_warning_clingo_warning_global_variable => Ok(Warning::GlobalVariable),
clingo_warning_clingo_warning_operation_undefined => Ok(Warning::OperationUndefined),
clingo_warning_clingo_warning_other => Ok(Warning::Other),
clingo_warning_clingo_warning_runtime_error => Ok(Warning::RuntimeError),
clingo_warning_clingo_warning_variable_unbounded => Ok(Warning::VariableUnbound),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_warning {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_warning.",
})
}
}
}
}
/// Enumeration of different external statements.
#[derive(Debug, Copy, Clone)]
pub enum ExternalType {
/// Allow an external to be assigned freely
Free = clingo_external_type_clingo_external_type_free as isize,
/// Assign an external to true
True = clingo_external_type_clingo_external_type_true as isize,
/// Assign an external to false
False = clingo_external_type_clingo_external_type_false as isize,
/// No longer treat an atom as external
Release = clingo_external_type_clingo_external_type_release as isize,
}
impl ExternalType {
fn try_from(code: i32) -> Result<ExternalType, ClingoError> {
match code as u32 {
clingo_external_type_clingo_external_type_false => Ok(ExternalType::False),
clingo_external_type_clingo_external_type_free => Ok(ExternalType::Free),
clingo_external_type_clingo_external_type_release => Ok(ExternalType::Release),
clingo_external_type_clingo_external_type_true => Ok(ExternalType::True),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_external_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_external_type.",
})
}
}
}
}
/// Enumeration of different heuristic modifiers.
#[derive(Debug, Copy, Clone)]
pub enum HeuristicType {
/// Set the level of an atom
Level = clingo_heuristic_type_clingo_heuristic_type_level as isize,
/// Configure which sign to chose for an atom
Sign = clingo_heuristic_type_clingo_heuristic_type_sign as isize,
/// Modify VSIDS factor of an atom
Factor = clingo_heuristic_type_clingo_heuristic_type_factor as isize,
/// Modify the initial VSIDS score of an atom
Init = clingo_heuristic_type_clingo_heuristic_type_init as isize,
/// Set the level of an atom and choose a positive sign
True = clingo_heuristic_type_clingo_heuristic_type_true as isize,
/// Set the level of an atom and choose a negative sign
False = clingo_heuristic_type_clingo_heuristic_type_false as isize,
}
impl HeuristicType {
fn try_from(code: i32) -> Result<HeuristicType, ClingoError> {
match code as u32 {
clingo_heuristic_type_clingo_heuristic_type_factor => Ok(HeuristicType::Factor),
clingo_heuristic_type_clingo_heuristic_type_false => Ok(HeuristicType::False),
clingo_heuristic_type_clingo_heuristic_type_init => Ok(HeuristicType::Init),
clingo_heuristic_type_clingo_heuristic_type_level => Ok(HeuristicType::Level),
clingo_heuristic_type_clingo_heuristic_type_sign => Ok(HeuristicType::Sign),
clingo_heuristic_type_clingo_heuristic_type_true => Ok(HeuristicType::True),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_heuristic_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_heuristic_type.",
})
}
}
}
}
/// Enumeration of theory term types.
#[derive(Debug, Copy, Clone)]
pub enum TheoryTermType {
/// A tuple term, e.g., `(1,2,3)`
Tuple = clingo_theory_term_type_clingo_theory_term_type_tuple as isize,
/// A list term, e.g., `[1,2,3]`
List = clingo_theory_term_type_clingo_theory_term_type_list as isize,
/// A set term, e.g., `{1,2,3}`
Set = clingo_theory_term_type_clingo_theory_term_type_set as isize,
/// A function term, e.g., `f(1,2,3)`
Function = clingo_theory_term_type_clingo_theory_term_type_function as isize,
/// A number term, e.g., `42`
Number = clingo_theory_term_type_clingo_theory_term_type_number as isize,
/// A symbol term, e.g., `c`
Symbol = clingo_theory_term_type_clingo_theory_term_type_symbol as isize,
}
impl TheoryTermType {
fn try_from(code: i32) -> Result<TheoryTermType, ClingoError> {
match code as u32 {
clingo_theory_term_type_clingo_theory_term_type_tuple => Ok(TheoryTermType::Tuple),
clingo_theory_term_type_clingo_theory_term_type_list => Ok(TheoryTermType::List),
clingo_theory_term_type_clingo_theory_term_type_set => Ok(TheoryTermType::Set),
clingo_theory_term_type_clingo_theory_term_type_function => {
Ok(TheoryTermType::Function)
}
clingo_theory_term_type_clingo_theory_term_type_number => Ok(TheoryTermType::Number),
clingo_theory_term_type_clingo_theory_term_type_symbol => Ok(TheoryTermType::Symbol),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_theory_term_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_theory_term_type.",
})
}
}
}
}
/// Enumeration for the different model types.
#[derive(Debug, Copy, Clone)]
pub enum ModelType {
/// The model represents a stable model.
StableModel = clingo_model_type_clingo_model_type_stable_model as isize,
/// The model represents a set of brave consequences.
BraveConsequences = clingo_model_type_clingo_model_type_brave_consequences as isize,
/// The model represents a set of cautious consequences.
CautiousConsequences = clingo_model_type_clingo_model_type_cautious_consequences as isize,
}
impl ModelType {
fn try_from(code: i32) -> Result<ModelType, ClingoError> {
match code as u32 {
clingo_model_type_clingo_model_type_stable_model => Ok(ModelType::StableModel),
clingo_model_type_clingo_model_type_brave_consequences => {
Ok(ModelType::BraveConsequences)
}
clingo_model_type_clingo_model_type_cautious_consequences => {
Ok(ModelType::CautiousConsequences)
}
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_model_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_model_type.",
})
}
}
}
}
/// Supported check modes for propagators.
#[derive(Debug, Copy, Clone)]
pub enum PropagatorCheckMode {
/// Do not call [`Propagator::check()`](trait.Propagator.html#method.check) at all
None = clingo_propagator_check_mode_clingo_propagator_check_mode_none as isize,
/// Call [`Propagator::check()`](trait.Propagator.html#method.check) on total assignment
Total = clingo_propagator_check_mode_clingo_propagator_check_mode_total as isize,
/// Call [`Propagator::check()`](trait.Propagator.html#method.check) on propagation fixpoints
Fixpoint = clingo_propagator_check_mode_clingo_propagator_check_mode_fixpoint as isize,
}
impl PropagatorCheckMode {
fn try_from(code: i32) -> Result<PropagatorCheckMode, ClingoError> {
match code as u32 {
clingo_propagator_check_mode_clingo_propagator_check_mode_fixpoint => {
Ok(PropagatorCheckMode::Fixpoint)
}
clingo_propagator_check_mode_clingo_propagator_check_mode_total => {
Ok(PropagatorCheckMode::Total)
}
clingo_propagator_check_mode_clingo_propagator_check_mode_none => {
Ok(PropagatorCheckMode::None)
}
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_propagator_check_mode {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_propagator_check_mode.",
})
}
}
}
}
bitflags! {
/// Bit flags describing the entries of a configuration.
pub struct ConfigurationType: u32 {
/// The entry is a (string) value.
const VALUE =
clingo_configuration_type_clingo_configuration_type_value;
/// The entry is an array.
const ARRAY =
clingo_configuration_type_clingo_configuration_type_array;
/// The entry is a map.
const MAP =
clingo_configuration_type_clingo_configuration_type_map;
}
}
bitflags! {
/// Bit flags describing solve modes.
pub struct SolveMode: u32 {
/// Enable non-blocking search.
const ASYNC = clingo_solve_mode_clingo_solve_mode_async;
/// Yield models in calls to clingo_solve_handle_model.
const YIELD = clingo_solve_mode_clingo_solve_mode_yield;
}
}
bitflags! {
/// Bit flags to select symbols in models.
pub struct ShowType: u32 {
/// Select CSP assignments.
const CSP = clingo_show_type_clingo_show_type_csp;
/// Select shown atoms and terms.
const SHOWN = clingo_show_type_clingo_show_type_shown;
/// Select all atoms.
const ATOMS = clingo_show_type_clingo_show_type_atoms;
/// Select all terms.
const TERMS = clingo_show_type_clingo_show_type_terms;
/// Select everything.
const ALL = clingo_show_type_clingo_show_type_all;
/// Select false instead of true atoms (Atoms) or terms (Terms)."
const COMPLEMENT = clingo_show_type_clingo_show_type_complement;
}
}
bitflags! {
/// Bit flags that describes the result of a solve call.
pub struct SolveResult: u32 {
/// The problem is satisfiable.
const SATISFIABLE = clingo_solve_result_clingo_solve_result_satisfiable;
/// The problem is unsatisfiable.
const UNSATISFIABLE =
clingo_solve_result_clingo_solve_result_unsatisfiable;
/// The search space was exhausted.
const EXHAUSTED = clingo_solve_result_clingo_solve_result_exhausted;
/// The search was interupted.
const INTERRUPTED = clingo_solve_result_clingo_solve_result_interrupted;
}
}
type SolveEventCallback = unsafe extern "C" fn(
type_: clingo_solve_event_type_t,
event: *mut c_void,
event_handler: *mut c_void,
goon: *mut bool,
) -> bool;
pub trait SolveEventHandler {
/// Callback function called during search to notify when the search is finished or a model is ready
///
/// **Attention:** If the search is finished, the model is NULL.
///
/// # Arguments
///
/// * `etype` - the type of the solve event
/// * `goon` - can be set to false to stop solving
///
/// **Returns** whether the call was successful
///
/// **See:** [`Control::solve()`](struct.Control.html#method.solve)
fn on_solve_event(&mut self, etype: SolveEventType, goon: &mut bool) -> bool;
#[doc(hidden)]
unsafe extern "C" fn unsafe_solve_callback<T: SolveEventHandler>(
etype: clingo_solve_event_type_t,
_event: *mut c_void,
event_handler: *mut c_void,
goon: *mut bool,
) -> bool {
// check for null pointers
if event_handler.is_null() | goon.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_solve_callback() got a null pointer.",
);
return false;
}
let event_handler = &mut *(event_handler as *mut T);
let goon = &mut *goon;
match SolveEventType::try_from(etype) {
Err(_) => {
// from the libclingo docs:
// If a (non-recoverable) clingo API function fails in this callback, it must return false.
// In case of errors not related to clingo, set error code ErrorType::Unknown and return false to stop solving with an error.
set_internal_error(ErrorType::Runtime, "Error in unsafe_solve_callback().");
false
}
Ok(etype) => event_handler.on_solve_event(etype, goon),
}
}
}
type AstCallback =
unsafe extern "C" fn(arg1: *const clingo_ast_statement_t, arg2: *mut c_void) -> bool;
pub trait StatementHandler {
/// Callback function called on an ast statement while traversing the ast.
///
/// **Returns** whether the call was successful
fn on_statement(&mut self, arg1: &ast::Statement) -> bool;
#[doc(hidden)]
unsafe extern "C" fn unsafe_ast_callback<T: StatementHandler>(
stm: *const clingo_ast_statement_t,
event_handler: *mut c_void,
) -> bool {
// check for null pointers
if stm.is_null() | event_handler.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_ast_callback() got a null pointer.",
);
return false;
}
let stm = &*(stm as *const ast::Statement);
let event_handler = &mut *(event_handler as *mut T);
event_handler.on_statement(stm)
}
}
type LoggingCallback =
unsafe extern "C" fn(code: clingo_warning_t, message: *const c_char, logger: *mut c_void);
/// An instance of this trait has to be registered with a solver to implement a custom logging.
pub trait Logger {
/// Callback to intercept warning messages.
///
/// # Arguments
///
/// * `code` - associated warning code
/// * `message` - warning message
///
/// **See:**
///
/// * [`Control::new_with_logger()`](struct.Control.html#method.new_with_logger)
/// * [`parse_term_with_logger()`](fn.parse_term_with_logger.html)
/// * [`parse_program_with_logger()`](fn.parse_program_with_logger.html)
fn log(&mut self, code: Warning, message: &str) {
print!("warn {:?}: {}", code, message);
}
#[doc(hidden)]
unsafe extern "C" fn unsafe_logging_callback<L: Logger>(
code: clingo_warning_t,
message: *const c_char,
logger: *mut c_void,
) {
// check for null pointers
if message.is_null() | logger.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_logging_callback() got a null pointer.",
);
return;
}
let message = CStr::from_ptr(message);
let logger = &mut *(logger as *mut L);
if let Err(e) = logger.try_logging_callback(code, message) {
eprintln!("Error in unsafe_logging_callback(): {}.", e);
set_internal_error(ErrorType::Runtime, "Error in unsafe_logging_callback().");
}
}
#[doc(hidden)]
fn try_logging_callback(
&mut self,
code: clingo_warning_t,
message: &CStr,
) -> Result<(), ClingoError> {
let code = Warning::try_from(code)?;
let message = message.to_str()?;
self.log(code, message);
Ok(())
}
}
type GroundCallback = unsafe extern "C" fn(
location: *const clingo_location_t,
name: *const c_char,
arguments: *const clingo_symbol_t,
arguments_size: usize,
event_handler: *mut c_void,
symbol_callback: clingo_symbol_callback_t,
symbol_callback_data: *mut c_void,
) -> bool;
pub trait ExternalFunctionHandler {
/// Callback function to implement external functions.
///
/// If an external function of form `@name(parameters)` occurs in a logic program,
/// then this function is called with its location, name, parameters, and a callback to inject symbols as arguments.
/// The callback can be called multiple times; all symbols passed are injected.
///
/// # Arguments
///
/// * `location` - location from which the external function was called
/// * `name` - name of the called external function
/// * `arguments` - arguments of the called external function
///
/// **Returns** a vector of symbols
///
/// **See:** [`Control::ground_with_event_handler()`](struct.Control.html#method.ground_with_event_handler)
///
/// The following example implements the external function `@f()` returning 42.
/// ```ignore
/// fn on_external_function(
/// &mut self,
/// _location: &Location,
/// name: &str,
/// arguments: &[Symbol],
/// ) -> Result<Vec<Symbol>,Error> {
/// if name == "f" && arguments.len() == 0 {
/// let symbol = Symbol::create_number(42);
/// Ok(vec![symbol])
/// } else {
/// Err(MyError{ msg: "function not found"})?
/// }
/// }
/// ```
fn on_external_function(
&mut self,
location: &Location,
name: &str,
arguments: &[Symbol],
) -> Result<Vec<Symbol>, ExternalError>;
#[doc(hidden)]
unsafe extern "C" fn unsafe_ground_callback<T: ExternalFunctionHandler>(
location: *const clingo_location_t,
name: *const c_char,
arguments: *const clingo_symbol_t,
arguments_size: usize,
event_handler: *mut c_void,
symbol_callback: clingo_symbol_callback_t,
symbol_callback_data: *mut c_void,
) -> bool {
// check for null pointers
if location.is_null()
| name.is_null()
| (arguments_size > 0 && arguments.is_null())
| event_handler.is_null()
{
set_internal_error(
ErrorType::Runtime,
"unsafe_ground_callback() got a null pointer.",
);
return false;
}
let location = &*(location as *const Location);
let name = CStr::from_ptr(name);
let arguments = std::slice::from_raw_parts(arguments as *const Symbol, arguments_size);
let event_handler = &mut *(event_handler as *mut T);
match event_handler.try_symbol_callback(
location,
name,
arguments,
symbol_callback,
symbol_callback_data,
) {
Ok(x) => x,
Err(e) => {
// from the libclingo docs:
// If a (non-recoverable) clingo API function fails in this callback, it must return false.
// In case of errors not related to clingo, set error code ErrorType::Unknown and return false to stop solving with an error.
eprintln!("Error in unsafe_ground_callback(): {}.", e);
set_internal_error(ErrorType::Runtime, "Error in unsafe_ground_callback().");
false
}
}
}
#[doc(hidden)]
fn try_symbol_callback(
&mut self,
location: &Location,
name: &CStr,
arguments: &[Symbol],
symbol_callback: clingo_symbol_callback_t,
symbol_callback_data: *mut c_void,
) -> Result<bool, ClingoError> {
let name = name.to_str()?;
let symbols = self.on_external_function(location, name, arguments)?;
if let Some(symbol_callback) = symbol_callback {
let v: Vec<clingo_symbol_t> = symbols.iter().map(|symbol| (*symbol).0).collect();
Ok(unsafe { symbol_callback(v.as_slice().as_ptr(), v.len(), symbol_callback_data) })
} else {
// no symbol callback
Ok(true)
}
}
}
/// Signed integer type used for aspif and solver literals.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Literal(clingo_literal_t);
impl Literal {
pub fn negate(self) -> Literal {
Literal(-(self.0))
}
pub fn get_integer(self) -> i32 {
self.0
}
}
impl From<Atom> for Literal{
fn from(atom: Atom) -> Literal {
Literal(atom.0 as i32)
}
}
impl From<Literal> for Atom{
fn from(lit: Literal) -> Self {
Atom(lit.0 as u32)
}
}
/// Unsigned integer type used for aspif atoms.
#[derive(Debug, Copy, Clone)]
pub struct Atom(clingo_atom_t);
/// Unsigned integer type used in various places.
#[derive(Debug, Copy, Clone)]
pub struct Id(clingo_id_t);
impl Id {
pub fn get_integer(self) -> u32 {
self.0
}
}
/// A Literal with an associated weight.
#[derive(Debug, Copy, Clone)]
pub struct WeightedLiteral(clingo_weighted_literal);
impl WeightedLiteral {
pub fn literal(self) -> Literal {
Literal(self.0.literal)
}
pub fn weight(self) -> i32 {
self.0.weight
}
}
/// Represents a source code location marking its beginning and end.
///
/// **Note:** Not all locations refer to physical files.
/// By convention, such locations use a name put in angular brackets as filename.
#[derive(Debug, Copy, Clone)]
pub struct Location(clingo_location);
impl Location {
/// Create a default location.
fn default() -> clingo_location {
let file = CString::new("").unwrap();
clingo_location {
begin_line: 0,
end_line: 0,
begin_column: 0,
end_column: 0,
begin_file: file.as_ptr(),
end_file: file.as_ptr(),
}
}
/// Create a new location.
///
/// # Arguments
///
/// - `begin_file` - the file where the location begins
/// - `end_file` - the file where the location ends
/// - `begin_line` - the line where the location begins
/// - `end_line` - the line where the location ends
/// - `begin_column` - the column where the location begins
/// - `end_column` - the column where the location ends
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `begin_file` `end_file` or contain a nul byte
pub fn new(
begin_file: &str,
end_file: &str,
begin_line: usize,
end_line: usize,
begin_column: usize,
end_column: usize,
) -> Result<Location, NulError> {
let begin_file = CString::new(begin_file)?;
let end_file = CString::new(end_file)?;
let loc = clingo_location {
begin_line,
end_line,
begin_column,
end_column,
begin_file: begin_file.as_ptr(),
end_file: end_file.as_ptr(),
};
Ok(Location(loc))
}