lapack_inject/backend.rs
1//! LP64/ILP64 dual backend for LAPACK function pointer registration.
2//!
3//! This module provides dual LP64/ILP64 fn pointer types and registration
4//! functions for each LAPACK function. Each function stores both an LP64 and
5//! an ILP64 provider via `OnceLock`, allowing runtime dispatch to whichever
6//! integer width the caller registered.
7//!
8//! Auto-generated from lapack-sys plus supplemental Netlib LAPACK routines.
9
10#![allow(non_camel_case_types)]
11#![allow(non_snake_case)]
12#![allow(clippy::too_many_arguments)]
13
14use std::ffi::c_char;
15use std::sync::OnceLock;
16
17use num_complex::{Complex32, Complex64};
18
19// =============================================================================
20// Select function types for eigenvalue routines
21// =============================================================================
22
23/// Select function type for real GEES (single)
24pub type SSelectFn2 = unsafe extern "C" fn(ar: *const f32, ai: *const f32) -> i32;
25/// Select function type for real GEES (double)
26pub type DSelectFn2 = unsafe extern "C" fn(ar: *const f64, ai: *const f64) -> i32;
27/// Select function type for real (single) with 3 args
28pub type SSelectFn3 = unsafe extern "C" fn(ar: *const f32, ai: *const f32, b: *const f32) -> i32;
29/// Select function type for real (double) with 3 args
30pub type DSelectFn3 = unsafe extern "C" fn(ar: *const f64, ai: *const f64, b: *const f64) -> i32;
31/// Select function type for complex GEES (single)
32pub type CSelectFn1 = unsafe extern "C" fn(w: *const Complex32) -> i32;
33/// Select function type for complex GEES (double)
34pub type ZSelectFn1 = unsafe extern "C" fn(w: *const Complex64) -> i32;
35/// Select function type for complex (single) with 2 args
36pub type CSelectFn2 = unsafe extern "C" fn(a: *const Complex32, b: *const Complex32) -> i32;
37/// Select function type for complex (double) with 2 args
38pub type ZSelectFn2 = unsafe extern "C" fn(a: *const Complex64, b: *const Complex64) -> i32;
39
40// =============================================================================
41// Macro for defining dual LP64/ILP64 function types, storage, and registration
42// =============================================================================
43
44/// Macro to define dual LP64/ILP64 LAPACK function pointer types,
45/// OnceLock storage, registration functions, and getter functions.
46macro_rules! define_dual_backend {
47 ($name:ident, $lp64_type:ty, $ilp64_type:ty) => {
48 paste::paste! {
49 static [<$name:upper _LP64>]: OnceLock<$lp64_type> = OnceLock::new();
50 static [<$name:upper _ILP64>]: OnceLock<$ilp64_type> = OnceLock::new();
51
52 /// Register the LP64 (i32) Fortran function pointer.
53 /// Returns 0 on success, 2 if already registered.
54 #[no_mangle]
55 pub unsafe extern "C" fn [<register_ $name _lp64>](f: $lp64_type) -> i32 {
56 match [<$name:upper _LP64>].set(f) {
57 Ok(()) => 0,
58 Err(_) => 2,
59 }
60 }
61
62 /// Register the ILP64 (i64) Fortran function pointer.
63 /// Returns 0 on success, 2 if already registered.
64 #[no_mangle]
65 pub unsafe extern "C" fn [<register_ $name _ilp64>](f: $ilp64_type) -> i32 {
66 match [<$name:upper _ILP64>].set(f) {
67 Ok(()) => 0,
68 Err(_) => 2,
69 }
70 }
71
72 /// Enum representing either an LP64 or ILP64 provider for this function.
73 #[allow(dead_code)]
74 pub enum [<$name:camel Provider>] {
75 Lp64($lp64_type),
76 Ilp64($ilp64_type),
77 }
78
79 /// Get the provider preferring LP64 (falls back to ILP64).
80 #[allow(dead_code)]
81 pub(crate) fn [<get_ $name _for_lp64>]() -> [<$name:camel Provider>] {
82 if let Some(f) = [<$name:upper _LP64>].get() {
83 return [<$name:camel Provider>]::Lp64(*f);
84 }
85 if let Some(f) = [<$name:upper _ILP64>].get() {
86 return [<$name:camel Provider>]::Ilp64(*f);
87 }
88 panic!(concat!(
89 "lapack function `", stringify!($name),
90 "` is not registered (call register_", stringify!($name),
91 "_lp64 or register_", stringify!($name), "_ilp64 first)"
92 ));
93 }
94
95 /// Get the provider preferring ILP64 (falls back to LP64).
96 #[allow(dead_code)]
97 pub(crate) fn [<get_ $name _for_ilp64>]() -> [<$name:camel Provider>] {
98 if let Some(f) = [<$name:upper _ILP64>].get() {
99 return [<$name:camel Provider>]::Ilp64(*f);
100 }
101 if let Some(f) = [<$name:upper _LP64>].get() {
102 return [<$name:camel Provider>]::Lp64(*f);
103 }
104 panic!(concat!(
105 "lapack function `", stringify!($name),
106 "` is not registered (call register_", stringify!($name),
107 "_lp64 or register_", stringify!($name), "_ilp64 first)"
108 ));
109 }
110 }
111 };
112}
113
114// =============================================================================
115// Generated function types and registrations
116// =============================================================================
117
118include!("backend_gen.rs");