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