playdate_sys/sys/
macros.rs1#[macro_export]
5macro_rules! println {
9 () => {{
10 $crate::log::println("")
11 }};
12
13 ($($arg:tt)*) => {{
14 $crate::log::println($crate::alloc::format!("{}", format_args!($($arg)*)));
15 }};
16}
17
18
19#[macro_export]
20macro_rules! api {
24 (/$($path:ident).*) => {
25 core::concat!("api", $(core::concat!(".", core::stringify!($path))),*)
26 };
27
28 ($($path:ident).*) => {{
29 unsafe {
30 $crate::api().expect("api")
31 $( .$path.as_ref().expect(core::stringify!($path)) )*
32 }
33 }};
34}
35
36#[macro_export]
37macro_rules! api_opt {
39 ($($path:ident).*) => {{
40 unsafe {
41 #![allow(unused_unsafe)]
42 $crate::api()
43 $( ?.$path.as_ref() )*
44 }
45 }};
46}
47
48#[macro_export]
49macro_rules! api_ok {
52 ($($path:ident).*) => {{
53 unsafe {
54 #![allow(unused_unsafe)]
55 #![allow(unused_imports)]
56 use $crate::error::OkOrNullErr as _;
57 use $crate::error::OkOrNullFnErr as _;
58
59 $crate::api().ok_or_null()
60 $( ?.$path.ok_or_null() )*
61 }
62 }};
63}
64
65#[cfg(feature = "error-ctx")]
66#[macro_export]
67macro_rules! api_ok_ctx {
70 ($($path:ident).*) => {{
71 unsafe {
72 #![allow(unused_unsafe)]
73 #![allow(unused_imports)]
74 use $crate::error::ctx::OkOrNullCtx as _;
75 use $crate::error::ctx::OkOrNullFnCtxErr as _;
76
77 $crate::api().ok_or_null_ctx("api")
79 $( ?.$path.ok_or_null_ctx( core::stringify!($path) ) )*
80 }
81 }};
82}
83
84
85#[macro_export]
86macro_rules! api_unchecked {
93 (/$($path:ident).*) => {
94 core::concat!("api", $(core::concat!(".", core::stringify!($path))),*)
95 };
96
97 ($($path:ident).*!) => {{
98 api_unchecked!($($path).*) .expect(api_unchecked!(/$($path).*))
99 }};
100
101 ($($path:ident).* $(!)?) => {{
102 $crate::API $( .read().$path )*
103 }};
104}
105
106
107#[cfg(test)]
108mod tests {
109 use core::ptr::null_mut;
110
111
112 #[allow(dead_code)]
114 fn api_unchecked() {
115 unsafe {
116 let _ = api_unchecked!(file);
117 let p = api_unchecked!(sound.channel);
118 (*p).newChannel.unwrap()();
119
120 let f = api_unchecked!(file.read!);
121 f(null_mut(), null_mut(), 0);
122
123 let f = api_unchecked!(file.read).unwrap();
124 f(null_mut(), null_mut(), 0);
125
126 let f = api_unchecked!(sound.channel.newChannel).unwrap();
127 f();
128 }
129 }
130
131 #[test]
132 #[should_panic(expected = "api")]
133 fn api() {
134 let f = api!(file.read);
135 unsafe { f(null_mut(), null_mut(), 0) };
136
137 let f = api!(sound.channel.newChannel);
138 unsafe { f() };
139 }
140
141
142 #[test]
143 fn try_api_opt() {
144 fn test() -> Option<()> {
145 unsafe {
146 api_opt!(file.read)?(null_mut(), null_mut(), 0);
147 api_opt!(sound.channel.newChannel)?();
148 }
149 Some(())
150 }
151
152 assert!(test().is_none());
153 }
154
155 #[test]
156 fn try_api_ok() {
157 fn test() -> Result<(), crate::error::NullPtrError> {
158 unsafe {
159 api_ok!(file.read)?(null_mut(), null_mut(), 0);
160 api_ok!(sound.channel.newChannel)?();
161 }
162 Ok(())
163 }
164
165 let res = test();
166 assert!(res.is_err());
167 }
168
169 #[test]
170 #[cfg(feature = "error-ctx")]
171 fn try_api_ok_ctx() {
172 fn test() -> Result<(), crate::error::ctx::NullPtrError> {
173 unsafe {
174 api_ok_ctx!(file.read)?(null_mut(), null_mut(), 0);
175 api_ok_ctx!(sound.channel.newChannel)?();
176 }
177
178 Ok(())
179 }
180 let res = test();
181 assert!(res.is_err());
182 assert_eq!("api", res.unwrap_err().ctx);
183 }
184}