···2626//
2727// Note that this is only valid to be called with options named by
2828// `ipdos_option_list`.
2929-IpdosValue ipdos_solver_option_get(const IpdosSolver *solver, const char *ident);
2929+IpdosValueRef ipdos_solver_option_get(const IpdosSolver *solver, const char *ident);
30303131// Set the current value of an option for the solver.
3232//
3333// Note that this is only valid to be called with options named by
3434// `ipdos_option_list`, and the value must be of the correct type.
3535-bool ipdos_solver_option_set(IpdosSolver *solver, const char *ident, IpdosValue value);
3535+bool ipdos_solver_option_set(IpdosSolver *solver, const char *ident, IpdosValueRef value);
36363737// Read an error message from the solver.
3838//
···4242void ipdos_solver_read_error(IpdosSolver *solver,
4343 void *context,
4444 void (*read_error)(void *context, const char *error));
4545+4646+// Run the solver with the given model
4747+IpdosStatus ipdos_solver_run(IpdosSolver *solver,
4848+ IpdosModelRef model,
4949+ void *context,
5050+ void (*on_solution)(void *context, IpdosSolutionRef solution));
5151+5252+// Returns the list of available statistical information that can be requested
5353+// from the solver and its solutions.
5454+IpdosStatisticList ipdos_statistic_list(void);
+173-79
c/ipdos_types.h
···11#ifndef ipdos_types_h
22#define ipdos_types_h
3344-#include <stdbool>
55-#include <stdint>
44+#include <stdbool.h>
55+#include <stdint.h>
6677// The status returned by `ipdos_solver_run`, indicating whether the solver
88// completed its search.
···3333} IpdosTypeBase;
34343535// Enumerated type used to mark the kind of [`IpdosValue`]. This is used to
3636-// determine which field in the [`IpdosValueContent`] union to access.
3636+// determine which "get" method in [`IpdosValueMethods`] is safe to call.
3737typedef enum IpdosValueKind {
3838- // No value is stored.
3838+ // No value is available.
3939 IpdosValueAbsent,
4040- // The value is stored in `decision_index`.
4040+ // The value is available using [`IpdosValueMethods::get_decision`].
4141 IpdosValueDecision,
4242- // The value is stored in `boolean_value`.
4343- IpdosValueBoolean,
4444- // The value is stored in `integer_value`.
4545- IpdosValueInteger,
4646- // The value is stored in `float_value`.
4242+ // The value is available using [`IpdosValueMethods::get_bool`].
4343+ IpdosValueBool,
4444+ // The value is available using [`IpdosValueMethods::get_int`].
4545+ IpdosValueInt,
4646+ // The value is available using [`IpdosValueMethods::get_float`].
4747 IpdosValueFloat,
4848- // The value is stored in `string_value`.
4848+ // The value is available using [`IpdosValueMethods::get_string`].
4949 IpdosValueString,
5050- // The value is stored in `list_value`.
5050+ // Sets of integers are represented using a range list. The number of
5151+ // ranges is available using [`IpdosValueMethods::len`], and the ranges can
5252+ // be accessed using [`IpdosValueMethods::get_range_int`].
5353+ IpdosValueSetInt,
5454+ // Sets of floats are represented using a range list. The number of
5555+ // ranges is available using [`IpdosValueMethods::len`], and the ranges can
5656+ // be accessed using [`IpdosValueMethods::get_range_float`].
5757+ IpdosValueSetFloat,
5858+ // The length of the list can be accessed using
5959+ // [`IpdosValueMethods::len`], and elements in the list can be
6060+ // accessed using [`IpdosValueMethods::get_element`]
5161 IpdosValueList,
5262} IpdosValueKind;
5363···108118// cast the pointer back to the original type, e.g. `(MyModel*) ipdos_model`.
109119typedef void IpdosModel;
110120111111-// The storage of the value content of a [`IpdosValue`].
112112-typedef union IpdosValueContent {
113113- // Decision index storage
114114- uint64_t decision_index;
115115- // Boolean value storage
116116- bool bool_value;
117117- // Integer value storage
118118- int64_t integer_value;
119119- // Float value storage
120120- double float_value;
121121- // Set of integers value storage
121121+// The type of a value used as an argument or solution assignment.
122122+//
123123+// This type is opaque to the user. Only pointers of this type are ever used.
124124+//
125125+// In implementation of the IPDOS interface, a pointer is generally cast to
126126+// this type, e.g. `(IpdosValue*) my_value`. A similar cast can be used to cast
127127+// the pointer back to the original type, e.g. `(MyValue*) ipdos_value`.
128128+typedef void IpdosValue;
129129+130130+// A struct containing the function pointers to interact with a
131131+// [`IpdosValue`]
132132+typedef struct IpdosValueMethods {
133133+ // Function callback that returns the kind of the value.
134134+ enum IpdosValueKind (*kind)(const IpdosValue*);
135135+ // Function callback that returns the length of the value.
122136 //
123123- // The set of integers is represented using a range list. The array of
124124- // `i64` values should be interpreted as a list of inclusive ranges,
125125- // where each range is represented by two values.
137137+ // In case [`IpdosValueMethods::kind`] returns
138138+ // [`IpdosValueKind::IpdosValueList`], the length is the number of elements
139139+ // in the list, accessible using [`IpdosValueMethods::get_element`].
126140 //
127127- // Note that the number of `i64` values is stored in the `len` field. Since
128128- // each range is represented by two values, it can be assumed that `len mod
129129- // 2 == 0`.
130130- const int64_t *set_of_int_value;
131131- // Set of floating point value storage
141141+ // In case [`IpdosValueMethods::kind`] returns
142142+ // [`IpdosValueKind::IpdosValueSetInt`] or
143143+ // [`IpdosValueKind::IpdosValueSetFloat`], the length is the number of
144144+ // ranges in the set, accessible using
145145+ // [`IpdosValueMethods::get_range_int`] or
146146+ // [`IpdosValueMethods::get_range_float`].
132147 //
133133- // The set of floating point values is represented using a range list. The
134134- // array of `f64` values should be interpreted as a list of inclusive
135135- // ranges, where each range is represented by two values.
148148+ // # Panics
136149 //
137137- // Note that the number of `f64` values is stored in the `len` field. Since
138138- // each range is represented by two values, it can be assumed that `len mod
139139- // 2 == 0`.
140140- const int64_t *set_of_float_value;
141141- // String value storage
150150+ // This function callback may panic if [`IpdosValueMethods::kind`] does not
151151+ // return [`IpdosValueKind::IpdosValueList`],
152152+ // [`IpdosValueKind::IpdosValueSetInt`], or
153153+ // [`IpdosValueKind::IpdosValueSetFloat`].
154154+ uint64_t (*len)(const IpdosValue*);
155155+ // Function callback that returns the decision variable index contained in
156156+ // the value.
142157 //
143143- // Note that the `string_value` field is intended to be interpreted as a
144144- // C-string. It should be \0 terminated, use UTF-8 encoding, and be valid
145145- // for the lifetime of the value.
146146- const char *string_value;
147147- // List value storage
158158+ // # Panics
148159 //
149149- // Note that the the number of elements in the list is stored in the `len`
150150- // field.
151151- const struct IpdosValue *list_value;
152152-} IpdosValueContent;
153153-154154-// The value representation used for values assigned to decision variables in
155155-// solution, as constraint/annotation arguments, and option parameters.
156156-typedef struct IpdosValue {
157157- // The kind of the value
160160+ // This function callback may panic if [`IpdosValueMethods::kind`] does not
161161+ // return [`IpdosValueKind::IpdosValueDecision`].
162162+ uint64_t (*get_decision)(const IpdosValue*);
163163+ // Function callback that returns the integer value contained in the value.
158164 //
159159- // This field is used to determine what field in the `value` union is
160160- // allowed to be accessed.
161161- enum IpdosValueKind kind;
162162- // A field containing the size of the value.
165165+ // # Panics
163166 //
164164- // This field is used when the value is a list, set of float/int, and
165165- // string, to determine the number of elements in the C array type.
166166- uint32_t len;
167167- // The storage of the actual data of the value.
168168- union IpdosValueContent content;
169169-} IpdosValue;
167167+ // This function callback may panic if [`IpdosValueMethods::kind`] does not
168168+ // return [`IpdosValueKind::IpdosValueInt`].
169169+ int64_t (*get_int)(const IpdosValue*);
170170+ // Function callback that returns the floating point value contained in the
171171+ // value.
172172+ //
173173+ // # Panics
174174+ //
175175+ // This function callback may panic if [`IpdosValueMethods::kind`] does not
176176+ // return [`IpdosValueKind::IpdosValueFloat`].
177177+ double (*get_float)(const IpdosValue*);
178178+ // Function callback that returns the string pointer value contained in the
179179+ // value.
180180+ //
181181+ // # Panics
182182+ //
183183+ // This function callback may panic if [`IpdosValueMethods::kind`] does not
184184+ // return [`IpdosValueKind::IpdosValueString`].
185185+ const char *(*get_string)(const IpdosValue*);
186186+ // Function callback that returns the Boolean value contained in the value.
187187+ //
188188+ // # Panics
189189+ //
190190+ // This function callback may panic if [`IpdosValueMethods::kind`] does not
191191+ // return [`IpdosValueKind::IpdosValueBool`].
192192+ bool (*get_bool)(const IpdosValue*);
193193+ // Function callback that returns a range from a range list representing
194194+ // the integer set contained in the value.
195195+ //
196196+ // # Panics
197197+ //
198198+ // This function callback may panic if [`IpdosValueMethods::kind`] does not
199199+ // return [`IpdosValueKind::IpdosValueSetInt`].
200200+ int64_t ((*get_range_int)(const IpdosValue*, uint64_t index))[2];
201201+ // Function callback that returns a range from a range list representing
202202+ // the floating point set contained in the value.
203203+ //
204204+ // # Panics
205205+ //
206206+ // This function callback may panic if [`IpdosValueMethods::kind`] does not
207207+ // return [`IpdosValueKind::IpdosValueSetFloat`].
208208+ double ((*get_range_float)(const IpdosValue*, uint64_t index))[2];
209209+ // Function callback that returns an element from the list contained in the
210210+ // value.
211211+ //
212212+ // # Panics
213213+ //
214214+ // This function callback may panic if [`IpdosValueMethods::kind`] does not
215215+ // return [`IpdosValueKind::IpdosValueList`].
216216+ struct IpdosValueRef (*get_element)(const IpdosValue*, uint64_t index);
217217+} IpdosValueMethods;
170218171171-// A struct containing the function pointers to interact with theIpdosModel`
219219+// Handle for a value
220220+//
221221+// The caller can use the `get_value` function to retrieve the value of the
222222+// used decision variables.
223223+typedef struct IpdosValueRef {
224224+ // The data pointer to be the first argument of `get_value`.
225225+ const IpdosValue *data;
226226+ // Reference to the structure containing the function callbacks used to
227227+ // interact with the value.
228228+ const struct IpdosValueMethods *methods;
229229+} IpdosValueRef;
230230+231231+// A struct containing the function pointers to interact with the
232232+// [`IpdosModel`]
172233typedef struct IpdosModelMethods {
173234 // Returns the current number of model layers currently contained in the
174235 // model.
···216277 //
217278 // Note that the the value might have [`IpdosValueKind::IpdosValueAbsent`]
218279 // if the decision variable does not have an explicit domain.
219219- struct IpdosValue (*decision_domain)(const IpdosModel *model, uint64_t decision);
280280+ struct IpdosValueRef (*decision_domain)(const IpdosModel *model, uint64_t decision);
220281 // Retrieve the name of a decision variable, if it exists.
221282 //
222283 // Note that names are only available for debugging purposes. Decisions are
···252313 //
253314 // The `index` argument must be less than the value returned by
254315 // `constraint_argument_len` for the given constraint.
255255- struct IpdosValue (*constraint_argument)(const IpdosModel *model,
256256- uint64_t constraint,
257257- uint64_t index);
316316+ struct IpdosValueRef (*constraint_argument)(const IpdosModel *model,
317317+ uint64_t constraint,
318318+ uint64_t index);
258319 // Check whether the decision variable is functionally defined by a
259320 // constraint.
260321 //
261322 // This function returns a [`IpdosValue`] that is either
262323 // [`IpdosValueKind::IpdosValueDecision`] if it defined a decision variable
263324 // or [`IpdosValueKind::IpdosValueAbsent`] otherwise.
264264- struct IpdosValue (*constraint_defines)(const IpdosModel *model, uint64_t decision);
325325+ struct IpdosValueRef (*constraint_defines)(const IpdosModel *model, uint64_t decision);
265326 // Retrieve the number of annotations on a constraint.
266327 uint64_t (*constraint_annotation_len)(const IpdosModel *model, uint64_t constraint);
267328 // Retrieve the annotation on a constraint at the given index.
···278339 // have an objective strategy.
279340 const char *(*objective_ident)(const IpdosModel *model);
280341 // Retrieve the argument of the objective strategy.
281281- struct IpdosValue (*objective_arg)(const IpdosModel *model);
342342+ struct IpdosValueRef (*objective_arg)(const IpdosModel *model);
282343 // Retrieve the number of annotations on an objective
283344 uint64_t (*objective_annotation_len)(const IpdosModel *model);
284345 // Retrieve the annotation on the objective at the given index.
···297358 //
298359 // The `index` argument must be less than the value returned by
299360 // `annotation_argument_len` for the given annotation.
300300- struct IpdosValue (*annotation_argument)(const IpdosAnnotation *ann, uint64_t index);
361361+ struct IpdosValueRef (*annotation_argument)(const IpdosAnnotation *ann, uint64_t index);
301362} IpdosModelMethods;
302363303364// An interface to a model instance used to communicate with the solver.
···337398 // option.
338399 const char *ident;
339400 // The type of value that is expected for this option.
340340- struct IpdosValue arg_ty;
401401+ struct IpdosValueRef arg_ty;
341402 // The default value for this option.
342403 struct IpdosType arg_def;
343404} IpdosOption;
···362423// ipdos_solution`.
363424typedef void IpdosSolution;
364425365365-// Structure used to represent a solution emitted by the solver.
366366-//
367367-// The caller can use the `get_value` function to retrieve the value of the
368368-// used decision variables.
426426+// A struct containing the function pointers to interact with a
427427+// [`IpdosSolution`]
428428+typedef struct IpdosSolutionMethods {
429429+ // Function callback to retrieve the value assigned to a decision variable
430430+ // in the solution.
431431+ struct IpdosValueRef (*get_value)(const IpdosSolution *data, uint64_t decision_index);
432432+ // Function callback to retrieve the statistical information made available
433433+ // by the solver about the search process so far.
434434+ struct IpdosValueRef (*get_statistic)(const IpdosSolution *data, const char *ident);
435435+} IpdosSolutionMethods;
436436+437437+// Handle for a solution emitted by the solver.
369438typedef struct IpdosSolutionRef {
370439 // The data pointer to be the first argument of `get_value`.
371440 const IpdosSolution *data;
372372- // Function callback to retrieve the value assigned to a decision variable
373373- // in the solution.
374374- struct IpdosValue (*get_value)(const IpdosSolution *data, uint64_t decision_index);
441441+ // Reference to the structure containing the function callbacks used to
442442+ // interact with the solution.
443443+ const struct IpdosSolutionMethods *methods;
375444} IpdosSolutionRef;
376445377446// The handle to a solver instance.
···383452// cast the pointer back to the original type, e.g. `(MySolverType*)
384453// ipdos_solver`.
385454typedef void IpdosSolver;
455455+456456+// The definition of statistical information that is made available by the
457457+// solver.
458458+typedef struct IpdosStatistic {
459459+ // The identifier used to retrieve the statistical information from the
460460+ // solver or a solution.
461461+ const char *ident;
462462+ // The type of value that is expected for this option.
463463+ struct IpdosValueRef ty;
464464+ // Whether the statistical information is available as part of solutions.
465465+ bool solution;
466466+ // Whether the statistical information is generally available from the
467467+ // solver instance.
468468+ bool solver;
469469+} IpdosStatistic;
470470+471471+// A list of [`IpdosStatistic`]s.
472472+//
473473+// This type is, for example, used to return from [`ipdos_statistic_list`].
474474+typedef struct IpdosStatisticList {
475475+ // The number of elements in the `stats` array.
476476+ uint64_t len;
477477+ // An array of statistical information definitions.
478478+ const struct IpdosStatistic *stats;
479479+} IpdosStatisticList;
386480387481// A list of [`IpdosType`]s.
388482//
···99use core::ffi;
10101111use ipdos_types::{
1212- IpdosConstraintList, IpdosModelRef, IpdosObjectiveList, IpdosOptionList, IpdosSolution,
1313- IpdosSolver, IpdosStatus, IpdosTypeList, IpdosValue,
1212+ IpdosConstraintList, IpdosModelRef, IpdosObjectiveList, IpdosOptionList, IpdosSolutionRef,
1313+ IpdosSolver, IpdosStatisticList, IpdosStatus, IpdosTypeList, IpdosValueRef,
1414};
15151616#[unsafe(no_mangle)]
···40404141#[unsafe(no_mangle)]
4242/// Create a new solver instance
4343-pub extern "C" fn ipdos_solver_create() -> Box<IpdosSolver> {
4343+pub extern "C" fn ipdos_solver_create() -> *mut IpdosSolver {
4444 unimplemented!()
4545}
4646···4949/// The pointer to the solver instance will be invalid after this function has
5050/// been called.
5151#[unsafe(no_mangle)]
5252-pub extern "C" fn ipdos_solver_free(solver: Box<IpdosSolver>) {
5252+pub extern "C" fn ipdos_solver_free(solver: *mut IpdosSolver) {
5353 let _ = solver;
5454 unimplemented!()
5555}
···6262pub extern "C" fn ipdos_solver_option_get(
6363 solver: &IpdosSolver,
6464 ident: *const ffi::c_char,
6565-) -> IpdosValue<'_> {
6565+) -> IpdosValueRef<'_> {
6666 let _ = solver;
6767 let _ = ident;
6868 unimplemented!()
···7676pub extern "C" fn ipdos_solver_option_set(
7777 solver: &mut IpdosSolver,
7878 ident: *const ffi::c_char,
7979- value: IpdosValue<'_>,
7979+ value: IpdosValueRef<'_>,
8080) -> bool {
8181 let _ = solver;
8282 let _ = ident;
···103103104104#[unsafe(no_mangle)]
105105/// Run the solver with the given model
106106-///
107107-/// cbindgen:no-export
108106pub extern "C" fn ipdos_solver_run(
109107 solver: &mut IpdosSolver,
110108 model: IpdosModelRef,
111109 context: &mut ffi::c_void,
112112- on_solution: extern "C" fn(context: &mut ffi::c_void, solution: &IpdosSolution),
110110+ on_solution: extern "C" fn(context: &mut ffi::c_void, solution: IpdosSolutionRef),
113111) -> IpdosStatus {
114112 let _ = solver;
115113 let _ = model;
···117115 let _ = on_solution;
118116 unimplemented!()
119117}
118118+119119+#[unsafe(no_mangle)]
120120+/// Returns the list of available statistical information that can be requested
121121+/// from the solver and its solutions.
122122+pub extern "C" fn ipdos_statistic_list() -> IpdosStatisticList<'static> {
123123+ unimplemented!()
124124+}
+228-201
rust/ipdos-types/src/lib.rs
···66//! unified way, and to allow the dynamic loading of solver libraries (as DLLs).
7788#![no_std]
99-use core::{ffi, fmt, marker::PhantomData, ptr::slice_from_raw_parts};
99+1010+use core::{ffi, marker::PhantomData};
10111112#[repr(transparent)]
1213#[derive(Debug)]
···22232324#[repr(C)]
2425#[derive(Clone, Debug)]
2525-/// Representation of a type of constraint, discerned by its identifier and the
2626-/// types of its arguments.
2727-pub struct IpdosConstraintType<'a> {
2828- /// The identifier of the constraint type.
2929- pub ident: *const ffi::c_char,
3030- /// The number of expected arguments for the constraint type.
3131- pub arg_len: u64,
3232- /// The types of the expected arguments for the constraint type.
3333- pub arg_types: *const IpdosType,
3434- /// The lifetime for which the `ident` and `arg_types` attributes are
3535- /// allocated.
3636- pub lifetime: PhantomData<&'a ()>,
3737-}
3838-3939-#[repr(C)]
4040-#[derive(Clone, Debug)]
4126/// A list of [`IpdosConstraintType`]s.
4227///
4328/// This type is for example used to return from [`ipdos_constraint_list`].
···5136}
52375338#[repr(C)]
5454-#[derive(Clone, Copy, Debug)]
5555-/// An interface to a model instance used to communicate with the solver.
5656-///
5757-/// The solver can use the included function callbacks to interact with the
5858-/// model.
5959-pub struct IpdosModelRef<'a> {
6060- /// The handle to the data of the model instance.
6161- data: &'a IpdosModel,
6262- /// Reference to the structure containing the function callbacks used to
6363- /// interact with the model.
6464- methods: &'static IpdosModelMethods,
3939+#[derive(Clone, Debug)]
4040+/// Representation of a type of constraint, discerned by its identifier and the
4141+/// types of its arguments.
4242+pub struct IpdosConstraintType<'a> {
4343+ /// The identifier of the constraint type.
4444+ pub ident: *const ffi::c_char,
4545+ /// The number of expected arguments for the constraint type.
4646+ pub arg_len: u64,
4747+ /// The types of the expected arguments for the constraint type.
4848+ pub arg_types: *const IpdosType,
4949+ /// The lifetime for which the `ident` and `arg_types` attributes are
5050+ /// allocated.
5151+ pub lifetime: PhantomData<&'a ()>,
6552}
66536754#[repr(transparent)]
···77647865#[repr(C)]
7966#[derive(Debug)]
8080-/// A struct containing the function pointers to interact with theIpdosModel`
6767+/// A struct containing the function pointers to interact with the
6868+/// [`IpdosModel`]
8169pub struct IpdosModelMethods {
8270 /// Returns the current number of model layers currently contained in the
8371 /// model.
···126114 ///
127115 /// Note that the the value might have [`IpdosValueKind::IpdosValueAbsent`]
128116 /// if the decision variable does not have an explicit domain.
129129- decision_domain: extern "C" fn(model: &IpdosModel, decision: u64) -> IpdosValue<'_>,
117117+ decision_domain: extern "C" fn(model: &IpdosModel, decision: u64) -> IpdosValueRef<'_>,
130118 /// Retrieve the name of a decision variable, if it exists.
131119 ///
132120 /// Note that names are only available for debugging purposes. Decisions are
···163151 /// The `index` argument must be less than the value returned by
164152 /// `constraint_argument_len` for the given constraint.
165153 constraint_argument:
166166- extern "C" fn(model: &IpdosModel, constraint: u64, index: u64) -> IpdosValue<'_>,
154154+ extern "C" fn(model: &IpdosModel, constraint: u64, index: u64) -> IpdosValueRef<'_>,
167155 /// Check whether the decision variable is functionally defined by a
168156 /// constraint.
169157 ///
170158 /// This function returns a [`IpdosValue`] that is either
171159 /// [`IpdosValueKind::IpdosValueDecision`] if it defined a decision variable
172160 /// or [`IpdosValueKind::IpdosValueAbsent`] otherwise.
173173- constraint_defines: extern "C" fn(model: &IpdosModel, decision: u64) -> IpdosValue<'_>,
161161+ constraint_defines: extern "C" fn(model: &IpdosModel, decision: u64) -> IpdosValueRef<'_>,
174162 /// Retrieve the number of annotations on a constraint.
175163 constraint_annotation_len: extern "C" fn(model: &IpdosModel, constraint: u64) -> u64,
176164 /// Retrieve the annotation on a constraint at the given index.
···187175 /// have an objective strategy.
188176 objective_ident: extern "C" fn(model: &IpdosModel) -> *const ffi::c_char,
189177 /// Retrieve the argument of the objective strategy.
190190- objective_arg: extern "C" fn(model: &IpdosModel) -> IpdosValue<'_>,
178178+ objective_arg: extern "C" fn(model: &IpdosModel) -> IpdosValueRef<'_>,
191179 /// Retrieve the number of annotations on an objective
192180 objective_annotation_len: extern "C" fn(model: &IpdosModel) -> u64,
193181 /// Retrieve the annotation on the objective at the given index.
···207195 ///
208196 /// The `index` argument must be less than the value returned by
209197 /// `annotation_argument_len` for the given annotation.
210210- annotation_argument: extern "C" fn(ann: &IpdosAnnotation, index: u64) -> IpdosValue<'_>,
198198+ annotation_argument: extern "C" fn(ann: &IpdosAnnotation, index: u64) -> IpdosValueRef<'_>,
199199+}
200200+201201+#[repr(C)]
202202+#[derive(Clone, Copy, Debug)]
203203+/// An interface to a model instance used to communicate with the solver.
204204+///
205205+/// The solver can use the included function callbacks to interact with the
206206+/// model.
207207+pub struct IpdosModelRef<'a> {
208208+ /// The handle to the data of the model instance.
209209+ data: &'a IpdosModel,
210210+ /// Reference to the structure containing the function callbacks used to
211211+ /// interact with the model.
212212+ methods: &'static IpdosModelMethods,
211213}
212214213215#[repr(C)]
···245247 /// option.
246248 pub ident: *const ffi::c_char,
247249 /// The type of value that is expected for this option.
248248- pub arg_ty: IpdosValue<'a>,
250250+ pub arg_ty: IpdosValueRef<'a>,
249251 /// The default value for this option.
250252 pub arg_def: IpdosType,
251253 /// The lifetime of the `ident` attribute.
···266268 pub lifetime: PhantomData<&'a ()>,
267269}
268270269269-#[repr(C)]
270270-#[derive(Clone, Debug)]
271271-/// Structure used to represent a solution emitted by the solver.
272272-///
273273-/// The caller can use the `get_value` function to retrieve the value of the
274274-/// used decision variables.
275275-pub struct IpdosSolutionRef<'a> {
276276- /// The data pointer to be the first argument of `get_value`.
277277- data: &'a IpdosSolution,
278278- /// Function callback to retrieve the value assigned to a decision variable
279279- /// in the solution.
280280- get_value: extern "C" fn(data: &IpdosSolution, decision_index: u64) -> IpdosValue<'_>,
281281-}
282282-283271#[repr(transparent)]
284272#[derive(Debug)]
285273/// The handle to a the data of a solution instance.
···292280/// ipdos_solution`.
293281pub struct IpdosSolution(ffi::c_void);
294282283283+#[repr(C)]
284284+#[derive(Clone, Debug)]
285285+/// A struct containing the function pointers to interact with a
286286+/// [`IpdosSolution`]
287287+pub struct IpdosSolutionMethods {
288288+ /// Function callback to retrieve the value assigned to a decision variable
289289+ /// in the solution.
290290+ get_value: extern "C" fn(data: &IpdosSolution, decision_index: u64) -> IpdosValueRef<'_>,
291291+ /// Function callback to retrieve the statistical information made available
292292+ /// by the solver about the search process so far.
293293+ get_statistic:
294294+ extern "C" fn(data: &IpdosSolution, ident: *const ffi::c_char) -> IpdosValueRef<'_>,
295295+}
296296+297297+#[repr(C)]
298298+#[derive(Clone, Debug)]
299299+/// Handle for a solution emitted by the solver.
300300+pub struct IpdosSolutionRef<'a> {
301301+ /// The data pointer to be the first argument of `get_value`.
302302+ data: &'a IpdosSolution,
303303+ /// Reference to the structure containing the function callbacks used to
304304+ /// interact with the solution.
305305+ methods: &'static IpdosSolutionMethods,
306306+}
307307+295308#[repr(transparent)]
296309#[derive(Debug)]
297310/// The handle to a solver instance.
···303316/// cast the pointer back to the original type, e.g. `(MySolverType*)
304317/// ipdos_solver`.
305318pub struct IpdosSolver(ffi::c_void);
319319+320320+#[repr(C)]
321321+#[derive(Clone, Debug)]
322322+/// The definition of statistical information that is made available by the
323323+/// solver.
324324+pub struct IpdosStatistic<'a> {
325325+ /// The identifier used to retrieve the statistical information from the
326326+ /// solver or a solution.
327327+ pub ident: *const ffi::c_char,
328328+ /// The type of value that is expected for this option.
329329+ pub ty: IpdosValueRef<'a>,
330330+ /// Whether the statistical information is available as part of solutions.
331331+ pub solution: bool,
332332+ /// Whether the statistical information is generally available from the
333333+ /// solver instance.
334334+ pub solver: bool,
335335+ /// The lifetime of the `ident` attribute.
336336+ pub lifetime: PhantomData<&'a ()>,
337337+}
338338+339339+#[repr(C)]
340340+#[derive(Clone, Debug)]
341341+/// A list of [`IpdosStatistic`]s.
342342+///
343343+/// This type is, for example, used to return from [`ipdos_statistic_list`].
344344+pub struct IpdosStatisticList<'a> {
345345+ /// The number of elements in the `stats` array.
346346+ pub len: u64,
347347+ /// An array of statistical information definitions.
348348+ pub stats: *const IpdosStatistic<'a>,
349349+ /// The lifetime of the `stats` attribute.
350350+ pub lifetime: PhantomData<&'a ()>,
351351+}
306352307353#[repr(C)]
308354#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
···369415 pub lifetime: PhantomData<&'a ()>,
370416}
371417372372-#[repr(C)]
373373-#[derive(Clone, Copy)]
374374-/// The value representation used for values assigned to decision variables in
375375-/// solution, as constraint/annotation arguments, and option parameters.
376376-pub struct IpdosValue<'a> {
377377- /// The kind of the value
378378- ///
379379- /// This field is used to determine what field in the `value` union is
380380- /// allowed to be accessed.
381381- pub kind: IpdosValueKind,
382382- /// A field containing the size of the value.
383383- ///
384384- /// This field is used when the value is a list, set of float/int, and
385385- /// string, to determine the number of elements in the C array type.
386386- pub len: u32,
387387- /// The storage of the actual data of the value.
388388- pub content: IpdosValueContent<'a>,
389389- /// Lifetime of the value (only relevant in Rust).
390390- pub lifetime: PhantomData<&'a ()>,
391391-}
392392-393393-#[repr(C)]
394394-#[derive(Clone, Copy)]
395395-/// The storage of the value content of a [`IpdosValue`].
396396-pub union IpdosValueContent<'a> {
397397- /// Decision index storage
398398- pub decision_index: u64,
399399- /// Boolean value storage
400400- pub bool_value: bool,
401401- /// Integer value storage
402402- pub integer_value: i64,
403403- /// Float value storage
404404- pub float_value: f64,
405405- /// Set of integers value storage
406406- ///
407407- /// The set of integers is represented using a range list. The array of
408408- /// `i64` values should be interpreted as a list of inclusive ranges,
409409- /// where each range is represented by two values.
410410- ///
411411- /// Note that the number of `i64` values is stored in the `len` field. Since
412412- /// each range is represented by two values, it can be assumed that `len mod
413413- /// 2 == 0`.
414414- pub set_of_int_value: *const i64,
415415- /// Set of floating point value storage
416416- ///
417417- /// The set of floating point values is represented using a range list. The
418418- /// array of `f64` values should be interpreted as a list of inclusive
419419- /// ranges, where each range is represented by two values.
420420- ///
421421- /// Note that the number of `f64` values is stored in the `len` field. Since
422422- /// each range is represented by two values, it can be assumed that `len mod
423423- /// 2 == 0`.
424424- pub set_of_float_value: *const i64,
425425- /// String value storage
426426- ///
427427- /// Note that the `string_value` field is intended to be interpreted as a
428428- /// C-string. It should be \0 terminated, use UTF-8 encoding, and be valid
429429- /// for the lifetime of the value.
430430- pub string_value: *const ffi::c_char,
431431- /// List value storage
432432- ///
433433- /// Note that the the number of elements in the list is stored in the `len`
434434- /// field.
435435- pub list_value: *const IpdosValue<'a>,
436436-}
418418+#[repr(transparent)]
419419+#[derive(Debug)]
420420+/// The type of a value used as an argument or solution assignment.
421421+///
422422+/// This type is opaque to the user. Only pointers of this type are ever used.
423423+///
424424+/// In implementation of the IPDOS interface, a pointer is generally cast to
425425+/// this type, e.g. `(IpdosValue*) my_value`. A similar cast can be used to cast
426426+/// the pointer back to the original type, e.g. `(MyValue*) ipdos_value`.
427427+pub struct IpdosValue(ffi::c_void);
437428438429#[repr(C)]
439430#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
440431/// Enumerated type used to mark the kind of [`IpdosValue`]. This is used to
441441-/// determine which field in the [`IpdosValueContent`] union to access.
432432+/// determine which "get" method in [`IpdosValueMethods`] is safe to call.
442433pub enum IpdosValueKind {
443443- /// No value is stored.
434434+ /// No value is available.
444435 IpdosValueAbsent,
445445- /// The value is stored in `decision_index`.
436436+ /// The value is available using [`IpdosValueMethods::get_decision`].
446437 IpdosValueDecision,
447447- /// The value is stored in `boolean_value`.
448448- IpdosValueBoolean,
449449- /// The value is stored in `integer_value`.
450450- IpdosValueInteger,
451451- /// The value is stored in `float_value`.
438438+ /// The value is available using [`IpdosValueMethods::get_bool`].
439439+ IpdosValueBool,
440440+ /// The value is available using [`IpdosValueMethods::get_int`].
441441+ IpdosValueInt,
442442+ /// The value is available using [`IpdosValueMethods::get_float`].
452443 IpdosValueFloat,
453453- /// The value is stored in `string_value`.
444444+ /// The value is available using [`IpdosValueMethods::get_string`].
454445 IpdosValueString,
455455- /// The value is stored in `list_value`.
446446+ /// Sets of integers are represented using a range list. The number of
447447+ /// ranges is available using [`IpdosValueMethods::len`], and the ranges can
448448+ /// be accessed using [`IpdosValueMethods::get_range_int`].
449449+ IpdosValueSetInt,
450450+ /// Sets of floats are represented using a range list. The number of
451451+ /// ranges is available using [`IpdosValueMethods::len`], and the ranges can
452452+ /// be accessed using [`IpdosValueMethods::get_range_float`].
453453+ IpdosValueSetFloat,
454454+ /// The length of the list can be accessed using
455455+ /// [`IpdosValueMethods::len`], and elements in the list can be
456456+ /// accessed using [`IpdosValueMethods::get_element`]
456457 IpdosValueList,
457458}
458459459459-impl fmt::Debug for IpdosValue<'_> {
460460- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461461- f.debug_struct("IpdosValue")
462462- .field("kind", &self.kind)
463463- .field("len", &self.len)
464464- // Safety: Access `self.content` according to the type information
465465- // provided explicitly by `self.kind`.
466466- .field("content", unsafe {
467467- match self.kind {
468468- IpdosValueKind::IpdosValueAbsent => &(),
469469- IpdosValueKind::IpdosValueDecision => &self.content.decision_index,
470470- IpdosValueKind::IpdosValueBoolean => &self.content.bool_value,
471471- IpdosValueKind::IpdosValueInteger => &self.content.integer_value,
472472- IpdosValueKind::IpdosValueFloat => &self.content.float_value,
473473- IpdosValueKind::IpdosValueString => &self.content.string_value,
474474- IpdosValueKind::IpdosValueList => &self.content.list_value,
475475- }
476476- })
477477- .field("lifetime", &self.lifetime)
478478- .finish()
479479- }
480480-}
481481-482482-impl PartialEq for IpdosValue<'_> {
483483- fn eq(&self, other: &Self) -> bool {
484484- self.kind == other.kind
485485- // Safety: Access `self.content` and `other.content` according to the type
486486- // information provided explicitly by `self.kind` and `other.kind`.
487487- && unsafe {
488488- match self.kind {
489489- IpdosValueKind::IpdosValueAbsent => true,
490490- IpdosValueKind::IpdosValueDecision => {
491491- self.content.decision_index == other.content.decision_index
492492- }
493493- IpdosValueKind::IpdosValueBoolean => {
494494- self.content.bool_value == other.content.bool_value
495495- }
496496- IpdosValueKind::IpdosValueInteger => {
497497- self.content.integer_value == other.content.integer_value
498498- }
499499- IpdosValueKind::IpdosValueFloat => {
500500- self.content.float_value == other.content.float_value
501501- }
502502- IpdosValueKind::IpdosValueString => {
503503- if self.len != other.len {
504504- return false;
505505- }
506506- if self.len == 0 {
507507- return true;
508508- }
509509- let self_str =
510510- &*slice_from_raw_parts(self.content.string_value, self.len as usize);
511511- let other_str =
512512- &*slice_from_raw_parts(other.content.string_value, other.len as usize);
513513- self_str == other_str
514514- }
515515- IpdosValueKind::IpdosValueList => {
516516- if self.len != other.len {
517517- return false;
518518- }
519519- let self_li =
520520- &*slice_from_raw_parts(self.content.list_value, self.len as usize);
521521- let other_li =
522522- &*slice_from_raw_parts(other.content.list_value, other.len as usize);
523523- self_li == other_li
524524- }
525525- }
526526- }
527527- }
460460+#[repr(C)]
461461+#[derive(Clone, Debug)]
462462+/// A struct containing the function pointers to interact with a
463463+/// [`IpdosValue`]
464464+pub struct IpdosValueMethods {
465465+ /// Function callback that returns the kind of the value.
466466+ kind: fn(&IpdosValue) -> IpdosValueKind,
467467+ /// Function callback that returns the length of the value.
468468+ ///
469469+ /// In case [`IpdosValueMethods::kind`] returns
470470+ /// [`IpdosValueKind::IpdosValueList`], the length is the number of elements
471471+ /// in the list, accessible using [`IpdosValueMethods::get_element`].
472472+ ///
473473+ /// In case [`IpdosValueMethods::kind`] returns
474474+ /// [`IpdosValueKind::IpdosValueSetInt`] or
475475+ /// [`IpdosValueKind::IpdosValueSetFloat`], the length is the number of
476476+ /// ranges in the set, accessible using
477477+ /// [`IpdosValueMethods::get_range_int`] or
478478+ /// [`IpdosValueMethods::get_range_float`].
479479+ ///
480480+ /// # Panics
481481+ ///
482482+ /// This function callback may panic if [`IpdosValueMethods::kind`] does not
483483+ /// return [`IpdosValueKind::IpdosValueList`],
484484+ /// [`IpdosValueKind::IpdosValueSetInt`], or
485485+ /// [`IpdosValueKind::IpdosValueSetFloat`].
486486+ len: fn(&IpdosValue) -> u64,
487487+ /// Function callback that returns the decision variable index contained in
488488+ /// the value.
489489+ ///
490490+ /// # Panics
491491+ ///
492492+ /// This function callback may panic if [`IpdosValueMethods::kind`] does not
493493+ /// return [`IpdosValueKind::IpdosValueDecision`].
494494+ get_decision: unsafe extern "C" fn(&IpdosValue) -> u64,
495495+ /// Function callback that returns the integer value contained in the value.
496496+ ///
497497+ /// # Panics
498498+ ///
499499+ /// This function callback may panic if [`IpdosValueMethods::kind`] does not
500500+ /// return [`IpdosValueKind::IpdosValueInt`].
501501+ get_int: unsafe extern "C" fn(&IpdosValue) -> i64,
502502+ /// Function callback that returns the floating point value contained in the
503503+ /// value.
504504+ ///
505505+ /// # Panics
506506+ ///
507507+ /// This function callback may panic if [`IpdosValueMethods::kind`] does not
508508+ /// return [`IpdosValueKind::IpdosValueFloat`].
509509+ get_float: unsafe extern "C" fn(&IpdosValue) -> f64,
510510+ /// Function callback that returns the string pointer value contained in the
511511+ /// value.
512512+ ///
513513+ /// # Panics
514514+ ///
515515+ /// This function callback may panic if [`IpdosValueMethods::kind`] does not
516516+ /// return [`IpdosValueKind::IpdosValueString`].
517517+ get_string: unsafe extern "C" fn(&IpdosValue) -> *const ffi::c_char,
518518+ /// Function callback that returns the Boolean value contained in the value.
519519+ ///
520520+ /// # Panics
521521+ ///
522522+ /// This function callback may panic if [`IpdosValueMethods::kind`] does not
523523+ /// return [`IpdosValueKind::IpdosValueBool`].
524524+ get_bool: unsafe extern "C" fn(&IpdosValue) -> bool,
525525+ /// Function callback that returns a range from a range list representing
526526+ /// the integer set contained in the value.
527527+ ///
528528+ /// # Panics
529529+ ///
530530+ /// This function callback may panic if [`IpdosValueMethods::kind`] does not
531531+ /// return [`IpdosValueKind::IpdosValueSetInt`].
532532+ get_range_int: unsafe extern "C" fn(&IpdosValue, index: u64) -> [i64; 2],
533533+ /// Function callback that returns a range from a range list representing
534534+ /// the floating point set contained in the value.
535535+ ///
536536+ /// # Panics
537537+ ///
538538+ /// This function callback may panic if [`IpdosValueMethods::kind`] does not
539539+ /// return [`IpdosValueKind::IpdosValueSetFloat`].
540540+ get_range_float: unsafe extern "C" fn(&IpdosValue, index: u64) -> [f64; 2],
541541+ /// Function callback that returns an element from the list contained in the
542542+ /// value.
543543+ ///
544544+ /// # Panics
545545+ ///
546546+ /// This function callback may panic if [`IpdosValueMethods::kind`] does not
547547+ /// return [`IpdosValueKind::IpdosValueList`].
548548+ get_element: unsafe extern "C" fn(&IpdosValue, index: u64) -> IpdosValueRef<'_>,
528549}
529550530530-impl fmt::Debug for IpdosValueContent<'_> {
531531- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
532532- // Safety: interprets the storage as raw 64 bits, no type information
533533- // necessary.
534534- write!(f, "{:#X}", unsafe { self.decision_index })
535535- }
551551+#[repr(C)]
552552+#[derive(Clone, Debug)]
553553+/// Handle for a value
554554+///
555555+/// The caller can use the `get_value` function to retrieve the value of the
556556+/// used decision variables.
557557+pub struct IpdosValueRef<'a> {
558558+ /// The data pointer to be the first argument of `get_value`.
559559+ data: &'a IpdosValue,
560560+ /// Reference to the structure containing the function callbacks used to
561561+ /// interact with the value.
562562+ methods: &'static IpdosValueMethods,
536563}
537564538565#[cfg(test)]
539566mod tests {
540540- use crate::{IpdosModelRef, IpdosSolutionRef, IpdosType, IpdosValue};
567567+ use crate::{IpdosModelRef, IpdosSolutionRef, IpdosType, IpdosValueRef};
541568542569 #[test]
543570 fn memory() {
544571 assert_eq!(size_of::<IpdosModelRef>(), size_of::<u128>());
545572 assert_eq!(size_of::<IpdosSolutionRef>(), size_of::<u128>());
546573 assert_eq!(size_of::<IpdosType>(), size_of::<u64>());
547547- assert_eq!(size_of::<IpdosValue>(), size_of::<u128>());
574574+ assert_eq!(size_of::<IpdosValueRef>(), size_of::<u128>());
548575 }
549576}