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