1#![no_std]
26
27extern crate alloc;
28
29#[cfg(test)]
30extern crate std;
31
32pub mod audio;
33pub mod backend;
34pub mod display;
35pub mod driver;
36pub mod heap;
37pub mod input;
38pub mod report;
39pub mod sdk;
40pub mod stack;
41pub mod storage;
42pub mod text;
43
44#[cfg(shuyi_playdate_sdk)]
45#[doc(hidden)]
46pub mod device;
47
48#[cfg(test)]
49mod fake;
50
51pub use backend::Playdate;
52pub use driver::Driver;
53pub use report::RunReport;
54
55#[cfg(shuyi_playdate_sdk)]
56pub use device::{pack, stack_high_water};
57
58#[cfg(not(shuyi_playdate_sdk))]
60pub fn pack() -> Result<&'static [u8], alloc::string::String> {
61 use alloc::borrow::ToOwned;
62 Err("the pack is on the device alone".to_owned())
64}
65
66#[cfg(not(shuyi_playdate_sdk))]
69pub fn stack_high_water() -> Option<usize> {
70 None
71}
72
73#[cfg(shuyi_playdate_sdk)]
79#[macro_export]
80macro_rules! main {
81 ($start:path) => {
82 $crate::main!(@entry $start, $crate::stack::DEFAULT_BYTES, None);
83 };
84 ($start:path, report = $report:expr) => {
85 $crate::main!(@entry $start, $crate::stack::DEFAULT_BYTES, Some($report));
86 };
87 ($start:path, stack_bytes = $bytes:expr) => {
88 $crate::main!(@entry $start, $bytes, None);
89 };
90 ($start:path, stack_bytes = $bytes:expr, report = $report:expr) => {
91 $crate::main!(@entry $start, $bytes, Some($report));
92 };
93 (@entry $start:path, $bytes:expr, $report:expr) => {
94 #[unsafe(no_mangle)]
96 pub extern "C" fn shuyi_playdate_init() {
97 let report: Option<$crate::RunReport> = $report;
98 $crate::device::init($start, $bytes, report);
99 }
100
101 #[unsafe(no_mangle)]
103 pub extern "C" fn shuyi_playdate_update() -> core::ffi::c_int {
104 $crate::device::update()
105 }
106
107 #[unsafe(no_mangle)]
109 pub extern "C" fn shuyi_playdate_event(event: core::ffi::c_int) {
110 $crate::device::event(event);
111 }
112
113 #[unsafe(no_mangle)]
115 pub extern "C" fn shuyi_playdate_menu_chosen(slot: core::ffi::c_int) {
116 $crate::device::menu_chosen(slot);
117 }
118 };
119}
120
121#[cfg(not(shuyi_playdate_sdk))]
127#[macro_export]
128macro_rules! main {
129 ($start:path) => {
130 const _: () = {
131 let _ = $start;
132 };
133 };
134 ($start:path, report = $report:expr) => {
135 const _: () = {
136 let _ = $start;
137 };
138 const _: fn() -> $crate::RunReport = || $report;
139 };
140 ($start:path, stack_bytes = $bytes:expr) => {
141 const _: () = {
142 let _ = $start;
143 let _: usize = $bytes;
144 };
145 };
146 ($start:path, stack_bytes = $bytes:expr, report = $report:expr) => {
147 const _: () = {
148 let _ = $start;
149 let _: usize = $bytes;
150 };
151 const _: fn() -> $crate::RunReport = || $report;
152 };
153}
154
155#[cfg(test)]
156mod tests {
157 use alloc::borrow::ToOwned;
158 use alloc::string::String;
159 use alloc::vec::Vec;
160
161 fn table(text: &str, name: &str) -> Vec<String> {
163 text.lines()
164 .skip_while(|l| l.trim() != name)
165 .skip(1)
166 .take_while(|l| !l.starts_with('['))
167 .map(|l| l.split('#').next().unwrap_or("").trim().to_owned())
168 .filter(|l| !l.is_empty())
169 .collect()
170 }
171
172 #[test]
173 fn off_the_device_there_is_no_pack() {
174 assert!(crate::pack().is_err());
175 }
176
177 #[test]
178 fn off_the_device_no_stack_is_measured() {
179 assert_eq!(crate::stack_high_water(), None);
180 }
181
182 #[test]
185 fn the_lints_are_the_workspace_lints_except_unsafe_code() {
186 let workspace = include_str!("../../../Cargo.toml");
187 let manifest = include_str!("../Cargo.toml");
188 let clippy = table(workspace, "[workspace.lints.clippy]");
189 assert!(clippy.len() > 5, "{clippy:?}");
190 let rust: Vec<String> = table(workspace, "[workspace.lints.rust]")
191 .iter()
192 .map(|l| l.replace("unsafe_code = \"forbid\"", "unsafe_code = \"deny\""))
193 .collect();
194 assert_eq!(table(manifest, "[lints.clippy]"), clippy);
195 assert_eq!(table(manifest, "[lints.rust]"), rust);
196 }
197}