From 3af9a49e89dd686d5487691ee7651d755e5096d3 Mon Sep 17 00:00:00 2001 From: Alex Dewar Date: Tue, 28 Apr 2026 20:06:17 +0100 Subject: [PATCH 1/4] Re-export `HighsOptionValue` There are potential uses for it outside the crate, so let's re-export it. Closes #39. --- src/lib.rs | 3 +-- src/options.rs | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 45f56de..6cc7301 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,10 +119,9 @@ use highs_sys::*; pub use matrix_col::{ColMatrix, Row}; pub use matrix_row::{Col, RowMatrix}; +pub use options::HighsOptionValue; pub use status::{HighsModelStatus, HighsSolutionStatus, HighsStatus}; -use crate::options::HighsOptionValue; - /// A problem where variables are declared first, and constraints are then added dynamically. /// See [`Problem`](Problem#impl-1). pub type RowProblem = Problem; diff --git a/src/options.rs b/src/options.rs index d83f82d..749d673 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,7 +1,9 @@ use std::ffi::{c_void, CStr, CString}; use std::os::raw::{c_char, c_int}; +/// A trait defining the possible value types for HiGHS model options pub trait HighsOptionValue { + /// Apply the given value to the given optino for the HiGHS model unsafe fn apply_to_highs(self, highs: *mut c_void, option: *const c_char) -> c_int; } From 8385c5c61c6cc50893e288c9ded7ddecb3dc6697 Mon Sep 17 00:00:00 2001 From: Alex Dewar Date: Tue, 28 Apr 2026 20:05:31 +0100 Subject: [PATCH 2/4] Remove trailing whitespace --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6cc7301..67d8a2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1070,6 +1070,4 @@ mod test { assert_eq!(status, highs_sys::STATUS_OK); assert_eq!(value, 2); } - - } From 72dfbb447cb4dc9f875be54b7106a869be740839 Mon Sep 17 00:00:00 2001 From: Alex Dewar Date: Tue, 28 Apr 2026 19:56:56 +0100 Subject: [PATCH 3/4] HighsPtr::set_option: Improve error messages --- src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 67d8a2a..bed8fc9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -708,10 +708,9 @@ impl HighsPtr { /// Set a custom parameter on the model pub fn set_option>, V: HighsOptionValue>(&mut self, option: STR, value: V) { - let c_str = CString::new(option).expect("invalid option name"); + let c_str = CString::new(option).expect("Option name contains NUL char"); let status = unsafe { value.apply_to_highs(self.mut_ptr(), c_str.as_ptr()) }; - try_handle_status(status, "Highs_setOptionValue") - .expect("An error was encountered in HiGHS."); + try_handle_status(status, "Highs_setOptionValue").expect("Failed to set model option"); } /// Number of variables From 5bd69abc5db3c3c61df261fb85a95aa1ad077c94 Mon Sep 17 00:00:00 2001 From: Alex Dewar Date: Tue, 28 Apr 2026 20:20:35 +0100 Subject: [PATCH 4/4] Add `Model::try_set_option` method for returning error in case setting option fails Closes #38. --- src/lib.rs | 40 ++++++++++++++++++++++++++++++++++------ src/options.rs | 21 ++++++++++++++++++++- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bed8fc9..67d3d67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,7 +119,7 @@ use highs_sys::*; pub use matrix_col::{ColMatrix, Row}; pub use matrix_row::{Col, RowMatrix}; -pub use options::HighsOptionValue; +pub use options::{HighsOptionValue, TrySetOptionError}; pub use status::{HighsModelStatus, HighsSolutionStatus, HighsStatus}; /// A problem where variables are declared first, and constraints are then added dynamically. @@ -387,7 +387,28 @@ impl Model { /// model.set_option("threads", 4); // solve on 4 threads /// ``` pub fn set_option>, V: HighsOptionValue>(&mut self, option: STR, value: V) { - self.highs.set_option(option, value) + self.try_set_option(option, value).unwrap() + } + + /// Try to set a custom parameter on the model, returning an error if it fails. + /// For the list of available options and their documentation, see: + /// + /// + /// It will fail if the option does not exist or the value is invalid. + /// + /// ``` + /// # use highs::ColProblem; + /// # use highs::Sense::Maximise; + /// let mut model = ColProblem::default().optimise(Maximise); + /// assert!(model.try_set_option("presolve", "off").is_ok()); // disable the presolver + /// assert!(model.try_set_option("made_up_option", true).is_err()); + /// ``` + pub fn try_set_option>, V: HighsOptionValue>( + &mut self, + option: STR, + value: V, + ) -> Result<(), TrySetOptionError> { + self.highs.try_set_option(option, value) } /// Set the number of threads to use when solving the model. @@ -702,15 +723,22 @@ impl HighsPtr { // setting log_file seems to cause a double free in Highs. // See https://github.com/rust-or/highs/issues/3 // self.set_option(&b"log_file"[..], ""); - self.set_option(&b"output_flag"[..], false); - self.set_option(&b"log_to_console"[..], false); + self.try_set_option(&b"output_flag"[..], false).unwrap(); + self.try_set_option(&b"log_to_console"[..], false).unwrap(); } /// Set a custom parameter on the model - pub fn set_option>, V: HighsOptionValue>(&mut self, option: STR, value: V) { + pub fn try_set_option>, V: HighsOptionValue>( + &mut self, + option: STR, + value: V, + ) -> Result<(), TrySetOptionError> { let c_str = CString::new(option).expect("Option name contains NUL char"); let status = unsafe { value.apply_to_highs(self.mut_ptr(), c_str.as_ptr()) }; - try_handle_status(status, "Highs_setOptionValue").expect("Failed to set model option"); + match try_handle_status(status, "Highs_setOptionValue") { + Ok(_) => Ok(()), + Err(_) => Err(TrySetOptionError {}), + } } /// Number of variables diff --git a/src/options.rs b/src/options.rs index 749d673..c846012 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,9 +1,28 @@ +use std::error::Error; use std::ffi::{c_void, CStr, CString}; +use std::fmt::{Debug, Display}; use std::os::raw::{c_char, c_int}; +/// An error occurred while trying to set a model option +#[derive(Debug, Clone)] +pub struct TrySetOptionError; + +impl Display for TrySetOptionError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Error setting model option") + } +} + +impl Error for TrySetOptionError {} + /// A trait defining the possible value types for HiGHS model options pub trait HighsOptionValue { - /// Apply the given value to the given optino for the HiGHS model + /// Apply the given value to the given option for the HiGHS model + /// + /// # Safety + /// + /// This function should only be called with valid pointers to `highs` and `option`. `option` + /// should be a NUL-terminated C-string. unsafe fn apply_to_highs(self, highs: *mut c_void, option: *const c_char) -> c_int; }