1use core::fmt;
2
3
4#[derive(Debug, PartialEq, Clone, Copy)]
5pub struct NullPtrError;
6
7impl core::error::Error for NullPtrError {
8 fn description(&self) -> &str { "" }
11}
12
13impl fmt::Display for NullPtrError {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "NullPtr") }
15}
16
17
18pub trait OkOrNullErr<T> {
19 fn ok_or_null<'a>(self) -> Result<&'a T, NullPtrError>;
20}
21
22impl<T> OkOrNullErr<T> for *const T {
23 fn ok_or_null<'a>(self) -> Result<&'a T, NullPtrError> { unsafe { self.as_ref() }.ok_or(NullPtrError) }
24}
25
26
27pub trait OkMutOrNullErr<T> {
28 fn ok_or_null<'a>(self) -> Result<&'a mut T, NullPtrError>;
29}
30
31impl<T> OkMutOrNullErr<T> for *mut T {
32 fn ok_or_null<'a>(self) -> Result<&'a mut T, NullPtrError> { unsafe { self.as_mut() }.ok_or(NullPtrError) }
33}
34
35
36pub trait OkOrNullFnErr<T> {
37 type Error: core::error::Error;
38 fn ok_or_null(self) -> Result<T, Self::Error>;
39}
40
41impl OkOrNullFnErr<&'static crate::ffi::PlaydateAPI> for crate::ApiRef {
42 type Error = NullPtrError;
43 fn ok_or_null(self) -> Result<&'static crate::ffi::PlaydateAPI, NullPtrError> { self.ok_or(NullPtrError) }
44}
45
46
47macro_rules! impl_fn_def {
48 ($($t:ident),*) => {
49 unsafe extern "C" fn($($t),*) -> R
50 };
51
52 ($($t:ident),*, ...) => {
53 unsafe extern "C" fn($($t),* ,...) -> R
54 }
55}
56
57macro_rules! impl_ok_or_null_fn_err {
58 ($($t:ident),*) => {
59 impl<R, $($t),*> OkOrNullFnErr<impl_fn_def!($($t),*)> for Option<impl_fn_def!($($t),*)> {
60 type Error = NullPtrError;
61 fn ok_or_null(self) -> Result<impl_fn_def!($($t),*), NullPtrError> {
62 self.ok_or(NullPtrError)
63 }
64 }
65
66 impl<'f, R, $($t),*> OkOrNullFnErr<&'f impl_fn_def!($($t),*)> for Option<&'f impl_fn_def!($($t),*)> {
67 type Error = NullPtrError;
68 fn ok_or_null(self) -> Result<&'f impl_fn_def!($($t),*), NullPtrError> {
69 self.ok_or(NullPtrError)
70 }
71 }
72 };
73
74 ($($t:ident),* ...) => {
75 impl_ok_or_null_fn_err!($($t),*);
76
77 impl<R, $($t),*> OkOrNullFnErr<impl_fn_def!($($t),* ,...)> for Option<impl_fn_def!($($t),* ,...)> {
78 type Error = NullPtrError;
79 fn ok_or_null(self) -> Result<impl_fn_def!($($t),* ,...), NullPtrError> {
80 self.ok_or(NullPtrError)
81 }
82 }
83
84 impl<'f, R, $($t),*> OkOrNullFnErr<&'f impl_fn_def!($($t),* ,...)> for Option<&'f impl_fn_def!($($t),* ,...)> {
85 type Error = NullPtrError;
86 fn ok_or_null(self) -> Result<&'f impl_fn_def!($($t),* ,...), NullPtrError> {
87 self.ok_or(NullPtrError)
88 }
89 }
90 };
91}
92
93
94impl_ok_or_null_fn_err!();
95impl_ok_or_null_fn_err!(A ...);
96impl_ok_or_null_fn_err!(A, B ...);
97impl_ok_or_null_fn_err!(A, B, C ...);
98impl_ok_or_null_fn_err!(A, B, C, D ...);
99impl_ok_or_null_fn_err!(A, B, C, D, E ...);
100impl_ok_or_null_fn_err!(A, B, C, D, E, F ...);
101impl_ok_or_null_fn_err!(A, B, C, D, E, F, G ...);
102impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H ...);
103impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I ...);
104impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J ...);
105impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J, K ...);
106impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J, K, L ...);
107impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J, K, L, M ...);
108impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J, K, L, M, N ...);
109impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O ...);
110
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116
117 fn api_access_ok_() -> Result<(), NullPtrError> {
119 crate::sys::api().ok_or_null()?.file.ok_or_null()?;
120 crate::sys::api().ok_or_null()?
121 .file
122 .ok_or_null()?
123 .open
124 .ok_or_null()?;
125 Ok(())
126 }
127
128 fn api_access_raw_() -> Result<(), NullPtrError> {
130 unsafe { crate::sys::API }.ok_or_null()?.file.ok_or_null()?;
131 unsafe { crate::sys::API }.ok_or_null()?
132 .file
133 .ok_or_null()?
134 .open
135 .ok_or_null()?;
136 Ok(())
137 }
138
139 #[test]
140 fn api_access_ok() { let _ = api_access_ok_; }
141
142 #[test]
143 fn api_access_raw() { let _ = api_access_raw_; }
144}
145
146
147#[cfg(feature = "error-ctx")]
148pub mod ctx {
149 use core::fmt;
150
151
152 #[derive(Debug)]
153 pub struct NullPtrError {
154 pub ctx: &'static str,
155 }
156
157 impl fmt::Display for NullPtrError {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Ptr to {} is null", self.ctx) }
159 }
160
161 impl Into<super::NullPtrError> for NullPtrError {
162 fn into(self) -> super::NullPtrError { super::NullPtrError }
165 }
166
167 impl core::error::Error for NullPtrError {
168 fn description(&self) -> &str { "" }
171 }
172
173 impl AsRef<str> for NullPtrError {
174 fn as_ref(&self) -> &str { self.ctx }
175 }
176
177
178 pub trait OkOrNullCtx<T> {
179 fn ok_or_null_ctx<'a>(self, ctx: &'static str) -> Result<&'a T, NullPtrError>;
180 }
181
182 impl<T> OkOrNullCtx<T> for *const T {
183 fn ok_or_null_ctx<'a>(self, ctx: &'static str) -> Result<&'a T, NullPtrError> {
184 unsafe { self.as_ref() }.ok_or(NullPtrError { ctx })
185 }
186 }
187
188
189 pub trait OkOrNullAddCtx<T> {
190 fn ctx(self, ctx: &'static str) -> Result<T, NullPtrError>;
192 }
193
194 impl<T> OkOrNullAddCtx<T> for Result<T, super::NullPtrError> {
195 fn ctx(self, ctx: &'static str) -> Result<T, NullPtrError> {
196 match self {
197 Ok(t) => Ok(t),
198 Err(_) => Err(NullPtrError { ctx }),
199 }
200 }
201 }
202
203
204 pub trait OkOrNullFnCtxErr<T> {
205 type Error: core::error::Error;
206 fn ok_or_null_ctx(self, ctx: &'static str) -> Result<T, Self::Error>;
207 }
208
209 impl OkOrNullFnCtxErr<&'static crate::ffi::PlaydateAPI> for crate::ApiRef {
210 type Error = NullPtrError;
211 fn ok_or_null_ctx(self, ctx: &'static str) -> Result<&'static crate::ffi::PlaydateAPI, NullPtrError> {
212 self.ok_or(NullPtrError { ctx })
213 }
214 }
215
216 macro_rules! impl_ok_or_null_fn_err {
217 ($($t:ident),*) => {
218 impl<R, $($t),*> OkOrNullFnCtxErr<impl_fn_def!($($t),*)> for Option<impl_fn_def!($($t),*)> {
219 type Error = NullPtrError;
220 fn ok_or_null_ctx(self, ctx: &'static str) -> Result<impl_fn_def!($($t),*), NullPtrError> {
221 self.ok_or(NullPtrError { ctx })
222 }
223 }
224 };
225 }
226
227 impl_ok_or_null_fn_err!();
228 impl_ok_or_null_fn_err!(A);
229 impl_ok_or_null_fn_err!(A, B);
230 impl_ok_or_null_fn_err!(A, B, C);
231 impl_ok_or_null_fn_err!(A, B, C, D);
232 impl_ok_or_null_fn_err!(A, B, C, D, E);
233 impl_ok_or_null_fn_err!(A, B, C, D, E, F);
234 impl_ok_or_null_fn_err!(A, B, C, D, E, F, G);
235 impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H);
236 impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I);
237 impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J);
238 impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J, K);
239 impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J, K, L);
240 impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J, K, L, M);
241 impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
242 impl_ok_or_null_fn_err!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
243
244
245 #[cfg(test)]
246 mod tests {
247 use super::*;
248
249
250 fn api_access_ok_() -> Result<(), NullPtrError> {
252 crate::sys::api().ok_or_null_ctx("api")?
253 .file
254 .ok_or_null_ctx("file")?;
255 crate::sys::api().ok_or_null_ctx("api")?
256 .file
257 .ok_or_null_ctx("file")?
258 .open
259 .ok_or_null_ctx("open")?;
260 Ok(())
261 }
262
263 fn api_access_raw_() -> Result<(), NullPtrError> {
265 unsafe { crate::sys::API }.ok_or_null_ctx("api")?
266 .file
267 .ok_or_null_ctx("file")?;
268 unsafe { crate::sys::API }.ok_or_null_ctx("api")?
269 .file
270 .ok_or_null_ctx("file")?
271 .open
272 .ok_or_null_ctx("open")?;
273 Ok(())
274 }
275
276 #[test]
277 fn api_access_ok() { let _ = api_access_ok_; }
278
279 #[test]
280 fn api_access_raw() { let _ = api_access_raw_; }
281 }
282}