Skip to main content

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");