1use crate::error_c::set_last_error;
2
3pub const DIFFSOL_OK: i32 = 0;
4pub const DIFFSOL_ERR: i32 = -1;
5pub const DIFFSOL_BAD_ARG: i32 = -2;
6
7pub trait CMapTo<Out> {
8 fn c_map_to(self) -> Out;
9}
10
11pub trait CMapFrom<In> {
12 fn c_map_from(value: In) -> Self;
13}
14
15macro_rules! impl_c_map_identity {
16 ($t:ty) => {
17 impl CMapTo<$t> for $t {
18 #[inline]
19 fn c_map_to(self) -> $t {
20 self
21 }
22 }
23
24 impl CMapFrom<$t> for $t {
25 #[inline]
26 fn c_map_from(value: $t) -> Self {
27 value
28 }
29 }
30 };
31}
32
33impl_c_map_identity!(i32);
34impl_c_map_identity!(usize);
35impl_c_map_identity!(u64);
36impl_c_map_identity!(i64);
37impl_c_map_identity!(f64);
38impl_c_map_identity!(f32);
39impl_c_map_identity!(bool);
40
41impl CMapTo<i32> for bool {
42 #[inline]
43 fn c_map_to(self) -> i32 {
44 if self { 1 } else { 0 }
45 }
46}
47
48impl CMapFrom<i32> for bool {
49 #[inline]
50 fn c_map_from(value: i32) -> Self {
51 value != 0
52 }
53}
54
55#[inline]
56pub fn map_get<In, Out>(value: In) -> Out
57where
58 In: CMapTo<Out>,
59{
60 value.c_map_to()
61}
62
63#[inline]
64pub fn map_set<In, Out>(value: In) -> Out
65where
66 Out: CMapFrom<In>,
67{
68 Out::c_map_from(value)
69}
70
71#[inline]
72pub fn invalid_arg_at(msg: &str, file: &'static str, line: u32) -> i32 {
73 set_last_error(msg, file, line);
74 DIFFSOL_BAD_ARG
75}
76
77#[inline]
78pub fn error_at(msg: &str, file: &'static str, line: u32) -> i32 {
79 set_last_error(msg, file, line);
80 DIFFSOL_ERR
81}
82
83#[inline]
84pub fn null_err_at<T>(ptr: *const T, msg: &str, file: &'static str, line: u32) -> bool {
85 if ptr.is_null() {
86 set_last_error(msg, file, line);
87 true
88 } else {
89 false
90 }
91}
92
93#[inline]
94pub fn valid_f64_ptr(ptr: *const f64, len: usize) -> bool {
95 len == 0 || !ptr.is_null()
96}
97
98#[macro_export]
99macro_rules! c_invalid_arg {
100 ($msg:expr) => {
101 $crate::c_api_utils::invalid_arg_at($msg, file!(), line!())
102 };
103}
104
105#[macro_export]
106macro_rules! c_error {
107 ($msg:expr) => {
108 $crate::c_api_utils::error_at($msg, file!(), line!())
109 };
110}
111
112#[macro_export]
113macro_rules! c_null_err {
114 ($ptr:expr, $msg:expr) => {
115 $crate::c_api_utils::null_err_at($ptr, $msg, file!(), line!())
116 };
117}
118
119#[macro_export]
120macro_rules! c_getter_simple {
121 ($prefix:ident, $opt_ty:ty, $out_ty:ty, $field:ident) => {
122 ::paste::paste! {
123 #[doc = "Get a solver option value."]
124 #[doc = ""]
125 #[doc = "# Safety"]
126 #[doc = "`options` must be a valid pointer created by this library. `out_value` must"]
127 #[doc = "be a valid, writable pointer for a single output value."]
128 #[unsafe(no_mangle)]
129 pub unsafe extern "C" fn [<$prefix _get_ $field>](options: *const $opt_ty, out_value: *mut $out_ty) -> i32 {
130 if options.is_null() || out_value.is_null() {
131 return $crate::c_invalid_arg!(concat!(
132 "invalid arguments to ",
133 stringify!([<$prefix _get_ $field>])
134 ));
135 }
136 let options = unsafe { &*options };
137 match options.[<get_ $field>]() {
138 Ok(value) => {
139 let mapped: $out_ty = $crate::c_api_utils::map_get::<_, $out_ty>(value);
140 unsafe {
141 *out_value = mapped;
142 }
143 $crate::c_api_utils::DIFFSOL_OK
144 }
145 Err(err) => $crate::c_error!(&format!("{}", err)),
146 }
147 }
148 }
149 };
150}
151
152#[macro_export]
153macro_rules! c_setter_simple {
154 ($prefix:ident, $opt_ty:ty, $in_ty:ty, $field:ident) => {
155 ::paste::paste! {
156 #[doc = "Set a solver option value."]
157 #[doc = ""]
158 #[doc = "# Safety"]
159 #[doc = "`options` must be a valid mutable pointer created by this library."]
160 #[unsafe(no_mangle)]
161 pub unsafe extern "C" fn [<$prefix _set_ $field>](options: *mut $opt_ty, value: $in_ty) -> i32 {
162 if options.is_null() {
163 return $crate::c_invalid_arg!(concat!(
164 "invalid arguments to ",
165 stringify!([<$prefix _set_ $field>])
166 ));
167 }
168 let options = unsafe { &mut *options };
169 let mapped = $crate::c_api_utils::map_set::<$in_ty, _>(value);
170 match options.[<set_ $field>](mapped) {
171 Ok(()) => $crate::c_api_utils::DIFFSOL_OK,
172 Err(err) => $crate::c_error!(&format!("{}", err)),
173 }
174 }
175 }
176 };
177}