1#[cfg(any(
5 feature = "diffsl-external-dynamic",
6 feature = "diffsl-cranelift",
7 feature = "diffsl-llvm",
8))]
9use std::ffi::CStr;
10#[cfg(any(
11 feature = "diffsl-external-dynamic",
12 feature = "diffsl-cranelift",
13 feature = "diffsl-llvm",
14))]
15use std::os::raw::c_char;
16#[cfg(feature = "diffsl-external-dynamic")]
17use std::path::PathBuf;
18use std::ptr;
19
20use crate::c_error;
21#[cfg(any(
22 feature = "diffsl-external-dynamic",
23 feature = "diffsl-cranelift",
24 feature = "diffsl-llvm",
25))]
26use crate::c_invalid_arg;
27#[cfg(any(feature = "diffsl-cranelift", feature = "diffsl-llvm"))]
28use crate::jit_c::jit_backend_from_i32;
29use crate::ode::OdeWrapper;
30use crate::ode_c::parse_ode_new_common_args;
31use crate::scalar_type::ScalarType;
32
33#[cfg(any(feature = "external", feature = "diffsl-external-dynamic"))]
34#[repr(C)]
35#[derive(Clone, Copy, Debug)]
36pub struct DiffsolDepPair {
46 pub row: usize,
47 pub col: usize,
48}
49
50#[cfg(any(feature = "external", feature = "diffsl-external-dynamic"))]
51unsafe fn dependency_pairs_from_raw_parts(
52 deps_ptr: *const DiffsolDepPair,
53 deps_len: usize,
54) -> Vec<(usize, usize)> {
55 if deps_ptr.is_null() || deps_len == 0 {
56 Vec::new()
57 } else {
58 unsafe { std::slice::from_raw_parts(deps_ptr, deps_len) }
59 .iter()
60 .map(|pair| (pair.row, pair.col))
61 .collect()
62 }
63}
64
65#[cfg(any(feature = "diffsl-cranelift", feature = "diffsl-llvm"))]
66fn parse_ode_new_jit_args(
67 code: *const c_char,
68 matrix_type: i32,
69 linear_solver: i32,
70 ode_solver: i32,
71) -> Option<(
72 String,
73 crate::matrix_type::MatrixType,
74 crate::linear_solver_type::LinearSolverType,
75 crate::ode_solver_type::OdeSolverType,
76)> {
77 if code.is_null() {
78 c_invalid_arg!("code is null");
79 return None;
80 }
81 let code = unsafe { CStr::from_ptr(code) };
82 let code = match code.to_str() {
83 Ok(value) => value.to_owned(),
84 Err(_) => {
85 c_error!("code is not valid UTF-8");
86 return None;
87 }
88 };
89 let (matrix_type, linear_solver, ode_solver) =
90 parse_ode_new_common_args(matrix_type, linear_solver, ode_solver)?;
91 Some((code, matrix_type, linear_solver, ode_solver))
92}
93
94#[cfg(feature = "diffsl-external-dynamic")]
95fn parse_ode_new_external_dynamic_args(
96 path: *const c_char,
97 matrix_type: i32,
98 linear_solver: i32,
99 ode_solver: i32,
100) -> Option<(
101 PathBuf,
102 crate::matrix_type::MatrixType,
103 crate::linear_solver_type::LinearSolverType,
104 crate::ode_solver_type::OdeSolverType,
105)> {
106 if path.is_null() {
107 c_invalid_arg!("path is null");
108 return None;
109 }
110 let path = unsafe { CStr::from_ptr(path) };
111 let path = match path.to_str() {
112 Ok(value) => PathBuf::from(value),
113 Err(_) => {
114 c_error!("path is not valid UTF-8");
115 return None;
116 }
117 };
118 let (matrix_type, linear_solver, ode_solver) =
119 parse_ode_new_common_args(matrix_type, linear_solver, ode_solver)?;
120 Some((path, matrix_type, linear_solver, ode_solver))
121}
122
123#[cfg(feature = "external")]
124#[unsafe(no_mangle)]
131pub unsafe extern "C" fn diffsol_ode_new_external(
132 matrix_type: i32,
133 linear_solver: i32,
134 ode_solver: i32,
135 rhs_state_deps_ptr: *const DiffsolDepPair,
136 rhs_state_deps_len: usize,
137 rhs_input_deps_ptr: *const DiffsolDepPair,
138 rhs_input_deps_len: usize,
139 mass_state_deps_ptr: *const DiffsolDepPair,
140 mass_state_deps_len: usize,
141) -> *mut OdeWrapper {
142 let Some((matrix_type, linear_solver, ode_solver)) =
143 parse_ode_new_common_args(matrix_type, linear_solver, ode_solver)
144 else {
145 return ptr::null_mut();
146 };
147
148 let rhs_state_deps =
149 unsafe { dependency_pairs_from_raw_parts(rhs_state_deps_ptr, rhs_state_deps_len) };
150 let rhs_input_deps =
151 unsafe { dependency_pairs_from_raw_parts(rhs_input_deps_ptr, rhs_input_deps_len) };
152 let mass_state_deps =
153 unsafe { dependency_pairs_from_raw_parts(mass_state_deps_ptr, mass_state_deps_len) };
154
155 let scalar_type = ScalarType::F64;
156 match OdeWrapper::new_external(
157 rhs_state_deps,
158 rhs_input_deps,
159 mass_state_deps,
160 scalar_type,
161 matrix_type,
162 linear_solver,
163 ode_solver,
164 ) {
165 Ok(ode) => Box::into_raw(Box::new(ode)),
166 Err(err) => {
167 c_error!(&format!("{}", err));
168 ptr::null_mut()
169 }
170 }
171}
172
173#[cfg(feature = "diffsl-external-dynamic")]
174#[unsafe(no_mangle)]
182pub unsafe extern "C" fn diffsol_ode_new_external_dynamic(
183 path: *const c_char,
184 matrix_type: i32,
185 linear_solver: i32,
186 ode_solver: i32,
187 rhs_state_deps_ptr: *const DiffsolDepPair,
188 rhs_state_deps_len: usize,
189 rhs_input_deps_ptr: *const DiffsolDepPair,
190 rhs_input_deps_len: usize,
191 mass_state_deps_ptr: *const DiffsolDepPair,
192 mass_state_deps_len: usize,
193) -> *mut OdeWrapper {
194 let Some((path, matrix_type, linear_solver, ode_solver)) =
195 parse_ode_new_external_dynamic_args(path, matrix_type, linear_solver, ode_solver)
196 else {
197 return ptr::null_mut();
198 };
199
200 let rhs_state_deps =
201 unsafe { dependency_pairs_from_raw_parts(rhs_state_deps_ptr, rhs_state_deps_len) };
202 let rhs_input_deps =
203 unsafe { dependency_pairs_from_raw_parts(rhs_input_deps_ptr, rhs_input_deps_len) };
204 let mass_state_deps =
205 unsafe { dependency_pairs_from_raw_parts(mass_state_deps_ptr, mass_state_deps_len) };
206
207 let scalar_type = ScalarType::F64;
208 match OdeWrapper::new_external_dynamic(
209 path,
210 rhs_state_deps,
211 rhs_input_deps,
212 mass_state_deps,
213 scalar_type,
214 matrix_type,
215 linear_solver,
216 ode_solver,
217 ) {
218 Ok(ode) => Box::into_raw(Box::new(ode)),
219 Err(err) => {
220 c_error!(&format!("{}", err));
221 ptr::null_mut()
222 }
223 }
224}
225
226#[cfg(any(feature = "diffsl-cranelift", feature = "diffsl-llvm"))]
227#[unsafe(no_mangle)]
234pub unsafe extern "C" fn diffsol_ode_new_jit(
235 code: *const c_char,
236 jit_backend: i32,
237 matrix_type: i32,
238 linear_solver: i32,
239 ode_solver: i32,
240) -> *mut OdeWrapper {
241 let Some((code, matrix_type, linear_solver, ode_solver)) =
242 parse_ode_new_jit_args(code, matrix_type, linear_solver, ode_solver)
243 else {
244 return ptr::null_mut();
245 };
246 let jit_backend = match jit_backend_from_i32(jit_backend) {
247 Some(value) => value,
248 None => {
249 c_invalid_arg!("invalid jit_backend_type");
250 return ptr::null_mut();
251 }
252 };
253 let scalar_type = ScalarType::F64;
254 match OdeWrapper::new_jit(
255 &code,
256 jit_backend,
257 scalar_type,
258 matrix_type,
259 linear_solver,
260 ode_solver,
261 ) {
262 Ok(ode) => Box::into_raw(Box::new(ode)),
263 Err(err) => {
264 c_error!(&format!("{}", err));
265 ptr::null_mut()
266 }
267 }
268}