Flat White Vitriol - An incremental solver protocol for combinatorial solving using shared objects

feat: reorganize into protocol types and solver (DLL) template

dekker.one b79aa7c9 c9c4436d

verified
+343 -243
+1 -1
Cargo.toml
··· 1 1 [workspace] 2 2 3 - members = ["crates/ipdos_protocol"] 3 + members = ["rust/ipdos-solver-template","rust/ipdos-types"] 4 4 5 5 resolver = "2" 6 6
+2 -1
Justfile
··· 3 3 # Build the Huub solver 4 4 build: 5 5 cargo build 6 - cbindgen --config crates/ipdos_protocol/cbindgen.toml --crate ipdos_protocol --output crates/ipdos_protocol/ipdos_protocol.h 6 + cbindgen --config cbindgen_types.toml --crate ipdos-types --output c/ipdos_types.h 7 + cbindgen --config cbindgen_template.toml --crate ipdos-solver-template --output c/ipdos_solver_template.c 7 8 8 9 # Check the codebase using all CI linters 9 10 check:
+44
c/ipdos_solver_template.c
··· 1 + #include "ipdos_types.h" 2 + 3 + // Returns the list of available constraint that can be added to the solver. 4 + IpdosConstraintList ipdos_constraint_list(void); 5 + 6 + // Returns the list of types for which decision variable can be created by the 7 + // solver. 8 + IpdosTypeList ipdos_decision_list(void); 9 + 10 + // Returns the list of available objective that can be achieved by the solver. 11 + IpdosObjectiveList ipdos_objective_list(void); 12 + 13 + // Returns the list of available options that can be set of the solver. 14 + IpdosOptionList ipdos_option_list(void); 15 + 16 + // Create a new solver instance 17 + IpdosSolver *ipdos_solver_create(void); 18 + 19 + // Free a solver instance, releasing all resources associated with it. 20 + // 21 + // The pointer to the solver instance will be invalid after this function has 22 + // been called. 23 + void ipdos_solver_free(IpdosSolver *solver); 24 + 25 + // Get the current value of an option for the solver. 26 + // 27 + // Note that this is only valid to be called with options named by 28 + // `ipdos_option_list`. 29 + IpdosValue ipdos_solver_option_get(const IpdosSolver *solver, const char *ident); 30 + 31 + // Set the current value of an option for the solver. 32 + // 33 + // Note that this is only valid to be called with options named by 34 + // `ipdos_option_list`, and the value must be of the correct type. 35 + bool ipdos_solver_option_set(IpdosSolver *solver, const char *ident, IpdosValue value); 36 + 37 + // Read an error message from the solver. 38 + // 39 + // This function is expected to be called after solver interactions signal an 40 + // error has occurred. For example, if [`ipdos_solver_run`] returns 41 + // [`IpdosError`] or [`ipdos_solver_push`] returns `false`. 42 + void ipdos_solver_read_error(IpdosSolver *solver, 43 + void *context, 44 + void (*read_error)(void *context, const char *error));
+34
cbindgen_template.toml
··· 1 + language = "C" 2 + 3 + # Wrapping header contents 4 + documentation_style = "c99" 5 + no_includes = true 6 + includes = ["ipdos_types.h"] 7 + cpp_compat = false 8 + 9 + [parse] 10 + parse_deps = true 11 + 12 + [export] 13 + exclude = [ 14 + "IpdosAnnotation", 15 + "IpdosConstraintType", 16 + "IpdosConstraintList", 17 + "IpdosModelRef", 18 + "IpdosModel", 19 + "IpdosModelMethods", 20 + "IpdosObjective", 21 + "IpdosObjectiveList", 22 + "IpdosOption", 23 + "IpdosOptionList", 24 + "IpdosSolutionRef", 25 + "IpdosSolution", 26 + "IpdosSolver", 27 + "IpdosStatus", 28 + "IpdosType", 29 + "IpdosTypeBase", 30 + "IpdosTypeList", 31 + "IpdosValue", 32 + "IpdosValueContent", 33 + "IpdosValueKind", 34 + ]
+31
cbindgen_types.toml
··· 1 + language = "C" 2 + 3 + # Wrapping header contents 4 + include_guard = "ipdos_types_h" 5 + documentation_style = "c99" 6 + sys_includes = ["stdbool", "stdint"] 7 + no_includes = true 8 + 9 + [export] 10 + include = [ 11 + "IpdosAnnotation", 12 + "IpdosConstraintType", 13 + "IpdosConstraintList", 14 + "IpdosModelRef", 15 + "IpdosModel", 16 + "IpdosModelMethods", 17 + "IpdosObjective", 18 + "IpdosObjectiveList", 19 + "IpdosOption", 20 + "IpdosOptionList", 21 + "IpdosSolutionRef", 22 + "IpdosSolution", 23 + "IpdosSolver", 24 + "IpdosStatus", 25 + "IpdosType", 26 + "IpdosTypeBase", 27 + "IpdosTypeList", 28 + "IpdosValue", 29 + "IpdosValueContent", 30 + "IpdosValueKind", 31 + ]
-1
crates/ipdos_protocol/.gitignore
··· 1 - /target
+1 -1
crates/ipdos_protocol/Cargo.toml rust/ipdos-types/Cargo.toml
··· 1 1 [package] 2 - name = "ipdos_protocol" 2 + name = "ipdos-types" 3 3 repository.workspace = true 4 4 version.workspace = true 5 5 authors.workspace = true
-5
crates/ipdos_protocol/cbindgen.toml
··· 1 - language = "C" 2 - 3 - # Wrapping header contents 4 - include_guard = "ipdos_protocol_h" 5 - documentation_style = "c99"
+86 -125
crates/ipdos_protocol/ipdos_protocol.h c/ipdos_types.h
··· 1 - #ifndef ipdos_protocol_h 2 - #define ipdos_protocol_h 1 + #ifndef ipdos_types_h 2 + #define ipdos_types_h 3 3 4 - #include <stdarg.h> 5 - #include <stdbool.h> 6 - #include <stdint.h> 7 - #include <stdlib.h> 4 + #include <stdbool> 5 + #include <stdint> 8 6 9 7 // The status returned by `ipdos_solver_run`, indicating whether the solver 10 8 // completed its search. ··· 53 51 IpdosValueList, 54 52 } IpdosValueKind; 55 53 54 + // The handle to a the data of a solution instance. 55 + // 56 + // This type is opaque to the user. Only pointers of this type are ever used. 57 + // 58 + // In implementation of the IPDOS interface, a pointer is generally cast to 59 + // this type, i.e. `(IpdosSolutionData*) my_solution`. A similar cast can be 60 + // used to cast the pointer back to the original type, e.g. `(MySolution*) 61 + // ipdos_solution`. 62 + typedef void IpdosAnnotation; 63 + 56 64 // Representation of a type to signal and check whether an argument takes the 57 65 // correct type. 58 66 typedef struct IpdosType { ··· 91 99 const struct IpdosConstraintType *constraints; 92 100 } IpdosConstraintList; 93 101 94 - // A list of [`IpdosType`]s. 102 + // The handle of a model instance. 95 103 // 96 - // This type is for example used to return from [`ipdos_decision_list`]. 97 - typedef struct IpdosTypeList { 98 - // The number of elements in the `constraints` array. 99 - uint64_t len; 100 - // An array of constraint types. 101 - const struct IpdosType *types; 102 - } IpdosTypeList; 103 - 104 - // Representation of a type of objective strategies, discerned by its 105 - // identifier and the type of its argument. 106 - typedef struct IpdosObjective { 107 - // The identifier of the objective type. 108 - const char *ident; 109 - // The type of the expected argument for the constraint type. 110 - struct IpdosType arg_type; 111 - } IpdosObjective; 112 - 113 - // A list of [`IpdosObjective`]s. 104 + // This type is opaque to the user. Only pointers of this type are ever used. 114 105 // 115 - // This type is, for example, used to return from [`ipdos_objective_list`]. 116 - typedef struct IpdosObjectiveList { 117 - // The number of elements in the `options` array. 118 - uint64_t len; 119 - // An array of option definitions. 120 - const struct IpdosObjective *options; 121 - } IpdosObjectiveList; 106 + // In implementation of the IPDOS interface, a pointer is generally cast to 107 + // this type, i.e. `(IpdosModelData*) my_model`. A similar cast can be used to 108 + // cast the pointer back to the original type, e.g. `(MyModel*) ipdos_model`. 109 + typedef void IpdosModel; 122 110 123 111 // The storage of the value content of a [`IpdosValue`]. 124 112 typedef union IpdosValueContent { ··· 180 168 union IpdosValueContent content; 181 169 } IpdosValue; 182 170 183 - // The definition of an option that is available to be set for the solver. 184 - typedef struct IpdosOption { 185 - // The identifier used to set the option or get the current value of the 186 - // option. 187 - const char *ident; 188 - // The type of value that is expected for this option. 189 - struct IpdosValue arg_ty; 190 - // The default value for this option. 191 - struct IpdosType arg_def; 192 - } IpdosOption; 193 - 194 - // A list of [`IpdosOption`]s. 195 - // 196 - // This type is, for example, used to return from [`ipdos_option_list`]. 197 - typedef struct IpdosOptionList { 198 - // The number of elements in the `options` array. 199 - uint64_t len; 200 - // An array of option definitions. 201 - const struct IpdosOption *options; 202 - } IpdosOptionList; 203 - 204 - // The handle to a solver instance. 205 - // 206 - // This type is opaque to the user. Only pointers of this type are ever used. 207 - // 208 - // In implementation of the IPDOS interface, a pointer is generally cast to 209 - // this type, i.e. `(IpdosSolver*) my_solver`. A similar cast can be used to 210 - // cast the pointer back to the original type, e.g. `(MySolverType*) 211 - // ipdos_solver`. 212 - typedef void IpdosSolver; 213 - 214 - // The handle of a model instance. 215 - // 216 - // This type is opaque to the user. Only pointers of this type are ever used. 217 - // 218 - // In implementation of the IPDOS interface, a pointer is generally cast to 219 - // this type, i.e. `(IpdosModelData*) my_model`. A similar cast can be used to 220 - // cast the pointer back to the original type, e.g. `(MyModel*) ipdos_model`. 221 - typedef void IpdosModel; 222 - 223 - // The handle to a the data of a solution instance. 224 - // 225 - // This type is opaque to the user. Only pointers of this type are ever used. 226 - // 227 - // In implementation of the IPDOS interface, a pointer is generally cast to 228 - // this type, i.e. `(IpdosSolutionData*) my_solution`. A similar cast can be 229 - // used to cast the pointer back to the original type, e.g. `(MySolution*) 230 - // ipdos_solution`. 231 - typedef void IpdosAnnotation; 232 - 233 171 // A struct containing the function pointers to interact with theIpdosModel` 234 172 typedef struct IpdosModelMethods { 235 173 // Returns the current number of model layers currently contained in the ··· 374 312 const struct IpdosModelMethods *methods; 375 313 } IpdosModelRef; 376 314 315 + // Representation of a type of objective strategies, discerned by its 316 + // identifier and the type of its argument. 317 + typedef struct IpdosObjective { 318 + // The identifier of the objective type. 319 + const char *ident; 320 + // The type of the expected argument for the constraint type. 321 + struct IpdosType arg_type; 322 + } IpdosObjective; 323 + 324 + // A list of [`IpdosObjective`]s. 325 + // 326 + // This type is, for example, used to return from [`ipdos_objective_list`]. 327 + typedef struct IpdosObjectiveList { 328 + // The number of elements in the `options` array. 329 + uint64_t len; 330 + // An array of option definitions. 331 + const struct IpdosObjective *options; 332 + } IpdosObjectiveList; 333 + 334 + // The definition of an option that is available to be set for the solver. 335 + typedef struct IpdosOption { 336 + // The identifier used to set the option or get the current value of the 337 + // option. 338 + const char *ident; 339 + // The type of value that is expected for this option. 340 + struct IpdosValue arg_ty; 341 + // The default value for this option. 342 + struct IpdosType arg_def; 343 + } IpdosOption; 344 + 345 + // A list of [`IpdosOption`]s. 346 + // 347 + // This type is, for example, used to return from [`ipdos_option_list`]. 348 + typedef struct IpdosOptionList { 349 + // The number of elements in the `options` array. 350 + uint64_t len; 351 + // An array of option definitions. 352 + const struct IpdosOption *options; 353 + } IpdosOptionList; 354 + 377 355 // The handle to a the data of a solution instance. 378 356 // 379 357 // This type is opaque to the user. Only pointers of this type are ever used. ··· 384 362 // ipdos_solution`. 385 363 typedef void IpdosSolution; 386 364 387 - // Returns the list of available constraint that can be added to the solver. 388 - struct IpdosConstraintList ipdos_constraint_list(void); 389 - 390 - // Returns the list of types for which decision variable can be created by the 391 - // solver. 392 - struct IpdosTypeList ipdos_decision_list(void); 393 - 394 - // Returns the list of available objective that can be achieved by the solver. 395 - struct IpdosObjectiveList ipdos_objective_list(void); 396 - 397 - // Returns the list of available options that can be set of the solver. 398 - struct IpdosOptionList ipdos_option_list(void); 399 - 400 - // Create a new solver instance 401 - IpdosSolver *ipdos_solver_create(void); 402 - 403 - // Free a solver instance, releasing all resources associated with it. 365 + // Structure used to represent a solution emitted by the solver. 404 366 // 405 - // The pointer to the solver instance will be invalid after this function has 406 - // been called. 407 - void ipdos_solver_free(IpdosSolver *solver); 367 + // The caller can use the `get_value` function to retrieve the value of the 368 + // used decision variables. 369 + typedef struct IpdosSolutionRef { 370 + // The data pointer to be the first argument of `get_value`. 371 + const IpdosSolution *data; 372 + // Function callback to retrieve the value assigned to a decision variable 373 + // in the solution. 374 + struct IpdosValue (*get_value)(const IpdosSolution *data, uint64_t decision_index); 375 + } IpdosSolutionRef; 408 376 409 - // Get the current value of an option for the solver. 377 + // The handle to a solver instance. 410 378 // 411 - // Note that this is only valid to be called with options named by 412 - // `ipdos_option_list`. 413 - struct IpdosValue ipdos_solver_option_get(const IpdosSolver *solver, const char *ident); 414 - 415 - // Set the current value of an option for the solver. 379 + // This type is opaque to the user. Only pointers of this type are ever used. 416 380 // 417 - // Note that this is only valid to be called with options named by 418 - // `ipdos_option_list`, and the value must be of the correct type. 419 - bool ipdos_solver_option_set(IpdosSolver *solver, const char *ident, struct IpdosValue value); 381 + // In implementation of the IPDOS interface, a pointer is generally cast to 382 + // this type, i.e. `(IpdosSolver*) my_solver`. A similar cast can be used to 383 + // cast the pointer back to the original type, e.g. `(MySolverType*) 384 + // ipdos_solver`. 385 + typedef void IpdosSolver; 420 386 421 - // Read an error message from the solver. 387 + // A list of [`IpdosType`]s. 422 388 // 423 - // This function is expected to be called after solver interactions signal an 424 - // error has occurred. For example, if [`ipdos_solver_run`] returns 425 - // [`IpdosError`] or [`ipdos_solver_push`] returns `false`. 426 - void ipdos_solver_read_error(IpdosSolver *solver, 427 - void *context, 428 - void (*read_error)(void *context, const char *error)); 429 - 430 - // Run the solver with the given model 431 - enum IpdosStatus ipdos_solver_run(IpdosSolver *solver, 432 - struct IpdosModelRef model, 433 - void *context, 434 - void (*on_solution)(void *context, const IpdosSolution *solution)); 389 + // This type is for example used to return from [`ipdos_decision_list`]. 390 + typedef struct IpdosTypeList { 391 + // The number of elements in the `constraints` array. 392 + uint64_t len; 393 + // An array of constraint types. 394 + const struct IpdosType *types; 395 + } IpdosTypeList; 435 396 436 - #endif /* ipdos_protocol_h */ 397 + #endif /* ipdos_types_h */
+7 -109
crates/ipdos_protocol/src/lib.rs rust/ipdos-types/src/lib.rs
··· 1 - //! IPDOS Protocol 1 + //! IPDOS Protocol Types 2 2 //! 3 - //! This crate defines the IPDOS protocol, which allows the incremental usage of 4 - //! solvers that can solve decision and optimization problems. The goal of the 5 - //! interface is to easily use different solvers in a unified way. 3 + //! This crate defines the types of the IPDOS protocol, which allows the 4 + //! incremental usage of solvers that can solve decision and optimization 5 + //! problems. The goal of the interface is to easily use different solvers in a 6 + //! unified way, and to allow the dynamic loading of solver libraries (as DLLs). 6 7 7 - use core::fmt; 8 - use std::{ffi, marker::PhantomData, ptr::slice_from_raw_parts}; 8 + #![no_std] 9 + use core::{ffi, fmt, marker::PhantomData, ptr::slice_from_raw_parts}; 9 10 10 11 #[repr(transparent)] 11 12 #[derive(Debug)] ··· 453 454 IpdosValueString, 454 455 /// The value is stored in `list_value`. 455 456 IpdosValueList, 456 - } 457 - 458 - #[unsafe(no_mangle)] 459 - /// Returns the list of available constraint that can be added to the solver. 460 - pub extern "C" fn ipdos_constraint_list() -> IpdosConstraintList<'static> { 461 - unimplemented!() 462 - } 463 - 464 - #[unsafe(no_mangle)] 465 - /// Returns the list of types for which decision variable can be created by the 466 - /// solver. 467 - pub extern "C" fn ipdos_decision_list() -> IpdosTypeList<'static> { 468 - unimplemented!() 469 - } 470 - 471 - #[unsafe(no_mangle)] 472 - /// Returns the list of available objective that can be achieved by the solver. 473 - pub extern "C" fn ipdos_objective_list() -> IpdosObjectiveList<'static> { 474 - unimplemented!() 475 - } 476 - 477 - #[unsafe(no_mangle)] 478 - /// Returns the list of available options that can be set of the solver. 479 - pub extern "C" fn ipdos_option_list() -> IpdosOptionList<'static> { 480 - unimplemented!() 481 - } 482 - 483 - #[unsafe(no_mangle)] 484 - /// Create a new solver instance 485 - pub extern "C" fn ipdos_solver_create() -> Box<IpdosSolver> { 486 - unimplemented!() 487 - } 488 - 489 - /// Free a solver instance, releasing all resources associated with it. 490 - /// 491 - /// The pointer to the solver instance will be invalid after this function has 492 - /// been called. 493 - #[unsafe(no_mangle)] 494 - pub extern "C" fn ipdos_solver_free(solver: Box<IpdosSolver>) { 495 - let _ = solver; 496 - unimplemented!() 497 - } 498 - 499 - #[unsafe(no_mangle)] 500 - /// Get the current value of an option for the solver. 501 - /// 502 - /// Note that this is only valid to be called with options named by 503 - /// `ipdos_option_list`. 504 - pub extern "C" fn ipdos_solver_option_get( 505 - solver: &IpdosSolver, 506 - ident: *const ffi::c_char, 507 - ) -> IpdosValue<'_> { 508 - let _ = solver; 509 - let _ = ident; 510 - unimplemented!() 511 - } 512 - 513 - #[unsafe(no_mangle)] 514 - /// Set the current value of an option for the solver. 515 - /// 516 - /// Note that this is only valid to be called with options named by 517 - /// `ipdos_option_list`, and the value must be of the correct type. 518 - pub extern "C" fn ipdos_solver_option_set( 519 - solver: &mut IpdosSolver, 520 - ident: *const ffi::c_char, 521 - value: IpdosValue<'_>, 522 - ) -> bool { 523 - let _ = solver; 524 - let _ = ident; 525 - let _ = value; 526 - unimplemented!() 527 - } 528 - 529 - #[unsafe(no_mangle)] 530 - /// Read an error message from the solver. 531 - /// 532 - /// This function is expected to be called after solver interactions signal an 533 - /// error has occurred. For example, if [`ipdos_solver_run`] returns 534 - /// [`IpdosError`] or [`ipdos_solver_push`] returns `false`. 535 - pub extern "C" fn ipdos_solver_read_error( 536 - solver: &mut IpdosSolver, 537 - context: &mut ffi::c_void, 538 - read_error: extern "C" fn(context: &mut ffi::c_void, error: *const ffi::c_char), 539 - ) { 540 - let _ = solver; 541 - let _ = context; 542 - let _ = read_error; 543 - unimplemented!() 544 - } 545 - 546 - #[unsafe(no_mangle)] 547 - /// Run the solver with the given model 548 - pub extern "C" fn ipdos_solver_run( 549 - solver: &mut IpdosSolver, 550 - model: IpdosModelRef, 551 - context: &mut ffi::c_void, 552 - on_solution: extern "C" fn(context: &mut ffi::c_void, solution: &IpdosSolution), 553 - ) -> IpdosStatus { 554 - let _ = solver; 555 - let _ = model; 556 - let _ = context; 557 - let _ = on_solution; 558 - unimplemented!() 559 457 } 560 458 561 459 impl fmt::Debug for IpdosValue<'_> {
+18
rust/ipdos-solver-template/Cargo.toml
··· 1 + [package] 2 + name = "ipdos-solver-template" 3 + repository.workspace = true 4 + version.workspace = true 5 + authors.workspace = true 6 + edition.workspace = true 7 + license.workspace = true 8 + 9 + publish = false 10 + 11 + [lib] 12 + crate-type = ["cdylib"] 13 + 14 + [dependencies] 15 + ipdos-types = { path = "../ipdos-types" } 16 + 17 + [lints] 18 + workspace = true
+119
rust/ipdos-solver-template/src/lib.rs
··· 1 + //! IPDOS Protocol Solver Template 2 + //! 3 + //! This crate defines the solver functionality to be implemented IPDOS 4 + //! protocol, which allows the incremental usage of solvers that can solve 5 + //! decision and optimization problems. The goal of the interface is to easily 6 + //! use different solvers in a unified way, and to allow the dynamic loading of 7 + //! solver libraries (as DLLs). 8 + 9 + use core::ffi; 10 + 11 + use ipdos_types::{ 12 + IpdosConstraintList, IpdosModelRef, IpdosObjectiveList, IpdosOptionList, IpdosSolution, 13 + IpdosSolver, IpdosStatus, IpdosTypeList, IpdosValue, 14 + }; 15 + 16 + #[unsafe(no_mangle)] 17 + /// Returns the list of available constraint that can be added to the solver. 18 + pub extern "C" fn ipdos_constraint_list() -> IpdosConstraintList<'static> { 19 + unimplemented!() 20 + } 21 + 22 + #[unsafe(no_mangle)] 23 + /// Returns the list of types for which decision variable can be created by the 24 + /// solver. 25 + pub extern "C" fn ipdos_decision_list() -> IpdosTypeList<'static> { 26 + unimplemented!() 27 + } 28 + 29 + #[unsafe(no_mangle)] 30 + /// Returns the list of available objective that can be achieved by the solver. 31 + pub extern "C" fn ipdos_objective_list() -> IpdosObjectiveList<'static> { 32 + unimplemented!() 33 + } 34 + 35 + #[unsafe(no_mangle)] 36 + /// Returns the list of available options that can be set of the solver. 37 + pub extern "C" fn ipdos_option_list() -> IpdosOptionList<'static> { 38 + unimplemented!() 39 + } 40 + 41 + #[unsafe(no_mangle)] 42 + /// Create a new solver instance 43 + pub extern "C" fn ipdos_solver_create() -> Box<IpdosSolver> { 44 + unimplemented!() 45 + } 46 + 47 + /// Free a solver instance, releasing all resources associated with it. 48 + /// 49 + /// The pointer to the solver instance will be invalid after this function has 50 + /// been called. 51 + #[unsafe(no_mangle)] 52 + pub extern "C" fn ipdos_solver_free(solver: Box<IpdosSolver>) { 53 + let _ = solver; 54 + unimplemented!() 55 + } 56 + 57 + #[unsafe(no_mangle)] 58 + /// Get the current value of an option for the solver. 59 + /// 60 + /// Note that this is only valid to be called with options named by 61 + /// `ipdos_option_list`. 62 + pub extern "C" fn ipdos_solver_option_get( 63 + solver: &IpdosSolver, 64 + ident: *const ffi::c_char, 65 + ) -> IpdosValue<'_> { 66 + let _ = solver; 67 + let _ = ident; 68 + unimplemented!() 69 + } 70 + 71 + #[unsafe(no_mangle)] 72 + /// Set the current value of an option for the solver. 73 + /// 74 + /// Note that this is only valid to be called with options named by 75 + /// `ipdos_option_list`, and the value must be of the correct type. 76 + pub extern "C" fn ipdos_solver_option_set( 77 + solver: &mut IpdosSolver, 78 + ident: *const ffi::c_char, 79 + value: IpdosValue<'_>, 80 + ) -> bool { 81 + let _ = solver; 82 + let _ = ident; 83 + let _ = value; 84 + unimplemented!() 85 + } 86 + 87 + #[unsafe(no_mangle)] 88 + /// Read an error message from the solver. 89 + /// 90 + /// This function is expected to be called after solver interactions signal an 91 + /// error has occurred. For example, if [`ipdos_solver_run`] returns 92 + /// [`IpdosError`] or [`ipdos_solver_push`] returns `false`. 93 + pub extern "C" fn ipdos_solver_read_error( 94 + solver: &mut IpdosSolver, 95 + context: &mut ffi::c_void, 96 + read_error: extern "C" fn(context: &mut ffi::c_void, error: *const ffi::c_char), 97 + ) { 98 + let _ = solver; 99 + let _ = context; 100 + let _ = read_error; 101 + unimplemented!() 102 + } 103 + 104 + #[unsafe(no_mangle)] 105 + /// Run the solver with the given model 106 + /// 107 + /// cbindgen:no-export 108 + pub extern "C" fn ipdos_solver_run( 109 + solver: &mut IpdosSolver, 110 + model: IpdosModelRef, 111 + context: &mut ffi::c_void, 112 + on_solution: extern "C" fn(context: &mut ffi::c_void, solution: &IpdosSolution), 113 + ) -> IpdosStatus { 114 + let _ = solver; 115 + let _ = model; 116 + let _ = context; 117 + let _ = on_solution; 118 + unimplemented!() 119 + }