cplex_rs/
logging.rs

1use std::ffi::{c_char, c_void, CStr};
2
3pub type LoggingCallback = Option<unsafe extern "C" fn(*mut c_void, *const c_char)>;
4pub type LoggingClosure = Box<dyn Fn(&str) + Send>;
5
6pub(crate) const RESULTS_STREAM_IDX: usize = 0;
7pub(crate) const WARNING_STREAM_IDX: usize = 1;
8pub(crate) const ERROR_STREAM_IDX: usize = 2;
9pub(crate) const LOG_STREAM_IDX: usize = 3;
10
11pub(crate) const DEFAULT_LOGGING_CLOSURE: Option<(LoggingClosure, LoggingCallback)> = None;
12
13#[derive(Clone, Copy, Debug)]
14pub enum StreamType {
15    Results,
16    Warning,
17    Error,
18    Log,
19}
20
21impl StreamType {
22    pub(crate) fn as_index(&self) -> usize {
23        match self {
24            Self::Results => RESULTS_STREAM_IDX,
25            Self::Warning => WARNING_STREAM_IDX,
26            Self::Error => ERROR_STREAM_IDX,
27            Self::Log => LOG_STREAM_IDX,
28        }
29    }
30}
31
32pub(crate) fn get_trampoline<F: Fn(&str)>() -> LoggingCallback {
33    Some(trampoline::<F>)
34}
35
36unsafe extern "C" fn trampoline<F>(user_data: *mut c_void, msg: *const c_char)
37where
38    F: Fn(&str),
39{
40    let logging_closure = &mut *(user_data as *mut F);
41    let msg = CStr::from_ptr(msg);
42    for line in msg.to_string_lossy().lines() {
43        logging_closure(line);
44    }
45}