Skip to main content

diffsol_c/
ode_callbacks_c.rs

1use std::ptr;
2
3use crate::c_error;
4use crate::ode::OdeWrapper;
5use crate::ode_c::parse_ode_new_common_args;
6use crate::ode_callbacks::{
7    CallbackScalar, DiffsolOdeCallbacksF32, DiffsolOdeCallbacksF64, OdeCallbacksDesc,
8};
9
10/// Shared implementation of the `diffsol_ode_new_callbacks_f64` and `diffsol_ode_new_callbacks_f32` constructors.
11///
12/// # Safety
13/// `callbacks` must be null, or it must point to a valid `OdeCallbacksDesc<T>` that satisfies
14/// the conditions of [crate::ode_callbacks::OdeCallbacks::new].
15unsafe fn new_callbacks<T: CallbackScalar>(
16    callbacks: *const OdeCallbacksDesc<T>,
17    matrix_type: i32,
18    linear_solver: i32,
19    ode_solver: i32,
20) -> *mut OdeWrapper {
21    if callbacks.is_null() {
22        crate::c_invalid_arg!("callbacks is null");
23        return ptr::null_mut();
24    }
25    // copy the descriptor: the caller's struct need not outlive this call
26    let callbacks = unsafe { *callbacks };
27    let Some((matrix_type, linear_solver, ode_solver)) =
28        parse_ode_new_common_args(matrix_type, linear_solver, ode_solver)
29    else {
30        // ownership of `user_data` has passed to us, so free it on every failure path
31        // SAFETY: nothing else has taken ownership of `user_data` yet
32        unsafe { callbacks.free_user_data() };
33        return ptr::null_mut();
34    };
35    // from here on `OdeCallbacks` owns `user_data`, and frees it if construction fails
36    // SAFETY: the caller guarantees the conditions of `OdeCallbacks::new`
37    let ode =
38        unsafe { OdeWrapper::new_callbacks(callbacks, matrix_type, linear_solver, ode_solver) };
39    match ode {
40        Ok(ode) => Box::into_raw(Box::new(ode)),
41        Err(err) => {
42            c_error!(&format!("{}", err));
43            ptr::null_mut()
44        }
45    }
46}
47
48/// Construct an ODE wrapper from equations that `double` precision C callbacks give.
49///
50/// The `ode_callbacks` module documentation gives the meaning and the array lengths of each
51/// callback. Only `rhs` and `init` are necessary. The other callbacks can be `NULL`. If a solve
52/// needs a callback that is `NULL`, the solve fails. The error gives the name of the callback.
53///
54/// The library takes ownership of `callbacks->user_data`. If `callbacks->free_user_data` is not
55/// `NULL`, the library calls it one time. It calls it when `diffsol_ode_free` frees the wrapper.
56/// If the construction fails, it calls it before this function returns `NULL`.
57///
58/// # Safety
59/// - `callbacks` must be null, or it must point to a valid `DiffsolOdeCallbacksF64`.
60/// - Each function pointer must be null or a valid function with the documented signature.
61/// - Each function must stay valid until the wrapper is freed.
62/// - Each function must read and write only the documented array lengths.
63/// - Do not give the same `user_data` with a `free_user_data` to two wrappers.
64#[unsafe(no_mangle)]
65pub unsafe extern "C" fn diffsol_ode_new_callbacks_f64(
66    callbacks: *const DiffsolOdeCallbacksF64,
67    matrix_type: i32,
68    linear_solver: i32,
69    ode_solver: i32,
70) -> *mut OdeWrapper {
71    unsafe { new_callbacks(callbacks, matrix_type, linear_solver, ode_solver) }
72}
73
74/// Construct an ODE wrapper from equations that `float` precision C callbacks give.
75///
76/// This function is the same as `diffsol_ode_new_callbacks_f64`, but each scalar is a `float`.
77/// The solver also uses single precision.
78///
79/// # Safety
80/// See `diffsol_ode_new_callbacks_f64`, with `DiffsolOdeCallbacksF32` in place of
81/// `DiffsolOdeCallbacksF64`.
82#[unsafe(no_mangle)]
83pub unsafe extern "C" fn diffsol_ode_new_callbacks_f32(
84    callbacks: *const DiffsolOdeCallbacksF32,
85    matrix_type: i32,
86    linear_solver: i32,
87    ode_solver: i32,
88) -> *mut OdeWrapper {
89    unsafe { new_callbacks(callbacks, matrix_type, linear_solver, ode_solver) }
90}