1#![no_std]
2
3extern crate alloc;
4
5use alloc::vec::Vec;
6use core::fmt::{self, Write};
7
8mod sys {
9 #[link(wasm_import_module = "env")]
10 unsafe extern "C" {
11 pub fn GetWinSizeX() -> i32;
12 pub fn GetWinSizeY() -> i32;
13 pub fn SetWinSize(w: i32, h: i32);
14 pub fn GetScreenWidth() -> i32;
15 pub fn GetScreenHeight() -> i32;
16 pub fn DrawRect(x: i32, y: i32, w: i32, h: i32, color: u32);
17 pub fn DrawText(x: i32, y: i32, ptr: *const u8, len: i32, color: u32);
18 pub fn Print(ptr: *const u8, len: i32);
19
20 pub fn GetFileSize(path_ptr: *const u8, path_len: i32) -> i32;
21 pub fn ReadFile(path_ptr: *const u8, path_len: i32, out_ptr: *mut u8, max_len: i32) -> i32;
22 pub fn WriteFile(path_ptr: *const u8, path_len: i32, data_ptr: *const u8, data_len: i32) -> i32;
23 pub fn RmFile(path_ptr: *const u8, len: i32) -> i32;
24
25 pub fn PollEvent(out_ptr: *mut u8) -> i32;
26 pub fn Die(code: i32) -> i32;
27
28 pub fn PerfON() -> i32;
29 pub fn PerfOFF() -> i32;
30 }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum Event {
35 KeyDown(u16),
36 KeyUp(u16),
37 MouseLeftDown { x: i32, y: i32 },
38 MouseLeftUp { x: i32, y: i32 },
39 MouseRightDown { x: i32, y: i32 },
40 MouseRightUp { x: i32, y: i32 },
41 MouseMove { x: i32, y: i32 },
42 ScrollUp,
43 ScrollDown,
44}
45
46pub struct Stdout;
47
48impl Write for Stdout {
49 fn write_str(&mut self, s: &str) -> fmt::Result {
50 print(s);
51 Ok(())
52 }
53}
54
55#[macro_export]
56macro_rules! print {
57 ($($arg:tt)*) => {{
58 use core::fmt::Write;
59 let _ = write!($crate::Stdout, $($arg)*);
60 }};
61}
62
63#[macro_export]
64macro_rules! println {
65 () => ($crate::print!("\n"));
66 ($($arg:tt)*) => {{
67 $crate::print!($($arg)*);
68 $crate::print!("\n");
69 }};
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub struct Color(pub u32);
74
75impl Color {
76 pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
77 Self(((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
78 }
79 pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
80 Self(((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
81 }
82}
83
84pub struct Window;
85
86impl Window {
87 pub fn size() -> (i32, i32) {
88 unsafe { (sys::GetWinSizeX(), sys::GetWinSizeY()) }
89 }
90
91 pub fn set_size(width: i32, height: i32) {
92 unsafe { sys::SetWinSize(width, height) }
93 }
94
95 pub fn screen_size() -> (i32, i32) {
96 unsafe { (sys::GetScreenWidth(), sys::GetScreenHeight()) }
97 }
98}
99
100pub struct Graphics;
101
102impl Graphics {
103 pub fn draw_rect(x: i32, y: i32, w: i32, h: i32, color: u32) {
104 unsafe { sys::DrawRect(x, y, w, h, color) }
105 }
106
107 pub fn draw_text(x: i32, y: i32, text: &str, color: u32) {
108 unsafe {
109 sys::DrawText(x, y, text.as_ptr(), text.len() as i32, color);
110 }
111 }
112}
113
114pub fn print(text: &str) {
115 unsafe {
116 sys::Print(text.as_ptr(), text.len() as i32);
117 }
118}
119
120pub fn die(code: i32) {
121 unsafe {
122 sys::Die(code);
123 }
124}
125
126pub struct System;
127
128impl System {
129 pub unsafe fn performance_mode(state: bool) {
131 unsafe {
132 if state { sys::PerfON(); }
133 else { sys::PerfOFF(); }
134 }
135 }
136}
137
138pub struct Fs;
139pub const MAX_FILE_SIZE: i32 = 512 * 1024 * 1024;
140
141impl Fs {
142 pub fn get_file_size(path: &str) -> Result<i32, FsError> {
143 let res = unsafe { sys::GetFileSize(path.as_ptr(), path.len() as i32) };
144 if res >= 0 {
145 Ok(res)
146 } else {
147 Err(FsError::from_code(res))
148 }
149 }
150
151 pub fn read_file(path: &str) -> Result<Vec<u8>, i32> {
152 let size = unsafe { sys::GetFileSize(path.as_ptr(), path.len() as i32) };
153
154 if size < 0 {
155 return Err(size);
156 }
157
158 if size > MAX_FILE_SIZE {
159 return Err(-6);
160 }
161
162 let mut buffer = alloc::vec![0u8; size as usize];
163 let res = unsafe {
164 sys::ReadFile(
165 path.as_ptr(),
166 path.len() as i32,
167 buffer.as_mut_ptr(),
168 buffer.len() as i32,
169 )
170 };
171
172 if res >= 0 {
173 buffer.truncate(res as usize);
174 Ok(buffer)
175 } else {
176 Err(res)
177 }
178 }
179
180 pub fn write_file(path: &str, data: &[u8]) -> Result<(), FsError> {
181 let res = unsafe {
182 sys::WriteFile(
183 path.as_ptr(),
184 path.len() as i32,
185 data.as_ptr(),
186 data.len() as i32,
187 )
188 };
189
190 if res == 0 {
191 Ok(())
192 } else {
193 Err(FsError::from_code(res))
194 }
195 }
196
197 pub fn remove_file(path: &str) -> Result<(), FsError> {
198 let res = unsafe { sys::RmFile(path.as_ptr(), path.len() as i32) };
199
200 if res == 0 {
201 Ok(())
202 } else {
203 Err(FsError::from_code(res))
204 }
205 }
206}
207
208#[derive(Debug, Clone, Copy, PartialEq, Eq)]
209pub enum FsError {
210 NotFound,
211 PermissionDenied,
212 AlreadyExists,
213 DiskFull,
214 InvalidPath,
215 FileTooLarge,
216 Unknown(i32),
217}
218
219#[allow(non_upper_case_globals)]
220impl FsError {
221 pub const Dolbayob: Self = crate::FsError::NotFound;
222 pub const IdiNahui: Self = crate::FsError::PermissionDenied;
223 pub const AlreadyFucked: Self = crate::FsError::AlreadyExists;
224 pub const AssFull: Self = crate::FsError::DiskFull;
225 pub const YouInvalid: Self = crate::FsError::InvalidPath;
226 pub const DickTooLarge: Self = crate::FsError::FileTooLarge;
227
228 pub fn from_code(code: i32) -> Self {
229 match code {
230 -1 => Self::NotFound,
231 -2 => Self::PermissionDenied,
232 -3 => Self::AlreadyExists,
233 -4 => Self::DiskFull,
234 -5 => Self::InvalidPath,
235 -6 => Self::FileTooLarge,
236 c => Self::Unknown(c),
237 }
238 }
239
240 pub fn from_code_but_for_me(code: i32) -> Self {
241 match code {
242 -1 => Self::Dolbayob,
243 -2 => Self::IdiNahui,
244 -3 => Self::AlreadyFucked,
245 -4 => Self::AssFull,
246 -5 => Self::YouInvalid,
247 -6 => Self::DickTooLarge,
248 c => Self::Unknown(c),
249 }
250 }
251}
252
253pub fn poll_event() -> Option<Event> {
254 let mut buf = [0u8; 16];
255 let res = unsafe { sys::PollEvent(buf.as_mut_ptr()) };
256
257 if res == 0 {
258 return None;
259 }
260
261 match buf[0] {
262 1 => {
263 let code = u16::from_le_bytes([buf[1], buf[2]]);
264 Some(Event::KeyDown(code))
265 }
266 2 => {
267 let code = u16::from_le_bytes([buf[1], buf[2]]);
268 Some(Event::KeyUp(code))
269 }
270 3 => {
271 let x = i32::from_le_bytes([buf[1], buf[2], buf[3], buf[4]]);
272 let y = i32::from_le_bytes([buf[5], buf[6], buf[7], buf[8]]);
273 Some(Event::MouseLeftDown { x, y })
274 }
275 4 => {
276 let x = i32::from_le_bytes([buf[1], buf[2], buf[3], buf[4]]);
277 let y = i32::from_le_bytes([buf[5], buf[6], buf[7], buf[8]]);
278 Some(Event::MouseLeftUp { x, y })
279 }
280 5 => {
281 let x = i32::from_le_bytes([buf[1], buf[2], buf[3], buf[4]]);
282 let y = i32::from_le_bytes([buf[5], buf[6], buf[7], buf[8]]);
283 Some(Event::MouseRightDown { x, y })
284 }
285 6 => {
286 let x = i32::from_le_bytes([buf[1], buf[2], buf[3], buf[4]]);
287 let y = i32::from_le_bytes([buf[5], buf[6], buf[7], buf[8]]);
288 Some(Event::MouseRightUp { x, y })
289 }
290 7 => {
291 let x = i32::from_le_bytes([buf[1], buf[2], buf[3], buf[4]]);
292 let y = i32::from_le_bytes([buf[5], buf[6], buf[7], buf[8]]);
293 Some(Event::MouseMove { x, y })
294 }
295 8 => Some(Event::ScrollUp),
296 9 => Some(Event::ScrollDown),
297 _ => None,
298 }
299}