micro144-sdk 0.1.0

Micro144 OS userspace and system SDK
Documentation
#![no_std]

extern crate alloc;

use alloc::vec::Vec;
use core::fmt::{self, Write};

mod sys {
    #[link(wasm_import_module = "env")]
    unsafe extern "C" {
        pub fn GetWinSizeX() -> i32;
        pub fn GetWinSizeY() -> i32;
        pub fn SetWinSize(w: i32, h: i32);
        pub fn GetScreenWidth() -> i32;
        pub fn GetScreenHeight() -> i32;
        pub fn DrawRect(x: i32, y: i32, w: i32, h: i32, color: u32);
        pub fn DrawText(x: i32, y: i32, ptr: *const u8, len: i32, color: u32);
        pub fn Print(ptr: *const u8, len: i32);

        pub fn GetFileSize(path_ptr: *const u8, path_len: i32) -> i32;
        pub fn ReadFile(path_ptr: *const u8, path_len: i32, out_ptr: *mut u8, max_len: i32) -> i32;
        pub fn WriteFile(path_ptr: *const u8, path_len: i32, data_ptr: *const u8, data_len: i32) -> i32;
        pub fn RmFile(path_ptr: *const u8, len: i32) -> i32;

        pub fn PollEvent(out_ptr: *mut u8) -> i32;
        pub fn Die(code: i32) -> i32;
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Event {
    KeyDown(u16),
    KeyUp(u16),
    MouseLeftDown { x: i32, y: i32 },
    MouseLeftUp { x: i32, y: i32 },
    MouseRightDown { x: i32, y: i32 },
    MouseRightUp { x: i32, y: i32 },
    MouseMove { x: i32, y: i32 },
    ScrollUp,
    ScrollDown,
}

pub struct Stdout;

impl Write for Stdout {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        print(s);
        Ok(())
    }
}

#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => {{
        use core::fmt::Write;
        let _ = write!($crate::Stdout, $($arg)*);
    }};
}

#[macro_export]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($($arg:tt)*) => {{
        $crate::print!($($arg)*);
        $crate::print!("\n");
    }};
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Color(pub u32);

impl Color {
    pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
        Self(((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
    }
    pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
        Self(((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
    }
}

pub struct Window;

impl Window {
    pub fn size() -> (i32, i32) {
        unsafe { (sys::GetWinSizeX(), sys::GetWinSizeY()) }
    }

    pub fn set_size(width: i32, height: i32) {
        unsafe { sys::SetWinSize(width, height) }
    }

    pub fn screen_size() -> (i32, i32) {
        unsafe { (sys::GetScreenWidth(), sys::GetScreenHeight()) }
    }
}

pub struct Graphics;

impl Graphics {
    pub fn draw_rect(x: i32, y: i32, w: i32, h: i32, color: u32) {
        unsafe { sys::DrawRect(x, y, w, h, color) }
    }

    pub fn draw_text(x: i32, y: i32, text: &str, color: u32) {
        unsafe {
            sys::DrawText(x, y, text.as_ptr(), text.len() as i32, color);
        }
    }
}

pub fn print(text: &str) {
    unsafe {
        sys::Print(text.as_ptr(), text.len() as i32);
    }
}

pub fn die(code: i32) {
    unsafe {
        sys::Die(code);
    }
}

pub struct Fs;
pub const MAX_FILE_SIZE: i32 = 512 * 1024 * 1024;

impl Fs {
    pub fn get_file_size(path: &str) -> Result<i32, FsError> {
        let res = unsafe { sys::GetFileSize(path.as_ptr(), path.len() as i32) };
        if res >= 0 {
            Ok(res)
        } else {
            Err(FsError::from_code(res))
        }
    }

    pub fn read_file(path: &str) -> Result<Vec<u8>, i32> {
        let size = unsafe { sys::GetFileSize(path.as_ptr(), path.len() as i32) };

        if size < 0 {
            return Err(size);
        }

        if size > MAX_FILE_SIZE {
            return Err(-6);
        }

        let mut buffer = alloc::vec![0u8; size as usize];
        let res = unsafe {
            sys::ReadFile(
                path.as_ptr(),
                          path.len() as i32,
                          buffer.as_mut_ptr(),
                          buffer.len() as i32,
            )
        };

        if res >= 0 {
            buffer.truncate(res as usize);
            Ok(buffer)
        } else {
            Err(res)
        }
    }

    pub fn write_file(path: &str, data: &[u8]) -> Result<(), FsError> {
        let res = unsafe {
            sys::WriteFile(
                path.as_ptr(),
                           path.len() as i32,
                           data.as_ptr(),
                           data.len() as i32,
            )
        };

        if res == 0 {
            Ok(())
        } else {
            Err(FsError::from_code(res))
        }
    }

    pub fn remove_file(path: &str) -> Result<(), FsError> {
        let res = unsafe { sys::RmFile(path.as_ptr(), path.len() as i32) };

        if res == 0 {
            Ok(())
        } else {
            Err(FsError::from_code(res))
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FsError {
    NotFound,
    PermissionDenied,
    AlreadyExists,
    DiskFull,
    InvalidPath,
    FileTooLarge,
    Unknown(i32),
}

#[allow(non_upper_case_globals)]
impl FsError {
    pub const Dolbayob: Self = crate::FsError::NotFound;
    pub const IdiNahui: Self = crate::FsError::PermissionDenied;
    pub const AlreadyFucked: Self = crate::FsError::AlreadyExists;
    pub const AssFull: Self = crate::FsError::DiskFull;
    pub const YouInvalid: Self = crate::FsError::InvalidPath;
    pub const DickTooLarge: Self = crate::FsError::FileTooLarge;

    pub fn from_code(code: i32) -> Self {
        match code {
            -1 => Self::NotFound,
            -2 => Self::PermissionDenied,
            -3 => Self::AlreadyExists,
            -4 => Self::DiskFull,
            -5 => Self::InvalidPath,
            -6 => Self::FileTooLarge,
            c => Self::Unknown(c),
        }
    }

    pub fn from_code_but_for_me(code: i32) -> Self {
        match code {
            -1 => Self::Dolbayob,
            -2 => Self::IdiNahui,
            -3 => Self::AlreadyFucked,
            -4 => Self::AssFull,
            -5 => Self::YouInvalid,
            -6 => Self::DickTooLarge,
            c => Self::Unknown(c),
        }
    }
}

pub fn poll_event() -> Option<Event> {
    let mut buf = [0u8; 16];
    let res = unsafe { sys::PollEvent(buf.as_mut_ptr()) };

    if res == 0 {
        return None;
    }

    match buf[0] {
        1 => {
            let code = u16::from_le_bytes([buf[1], buf[2]]);
            Some(Event::KeyDown(code))
        }
        2 => {
            let code = u16::from_le_bytes([buf[1], buf[2]]);
            Some(Event::KeyUp(code))
        }
        3 => {
            let x = i32::from_le_bytes([buf[1], buf[2], buf[3], buf[4]]);
            let y = i32::from_le_bytes([buf[5], buf[6], buf[7], buf[8]]);
            Some(Event::MouseLeftDown { x, y })
        }
        4 => {
            let x = i32::from_le_bytes([buf[1], buf[2], buf[3], buf[4]]);
            let y = i32::from_le_bytes([buf[5], buf[6], buf[7], buf[8]]);
            Some(Event::MouseLeftUp { x, y })
        }
        5 => {
            let x = i32::from_le_bytes([buf[1], buf[2], buf[3], buf[4]]);
            let y = i32::from_le_bytes([buf[5], buf[6], buf[7], buf[8]]);
            Some(Event::MouseRightDown { x, y })
        }
        6 => {
            let x = i32::from_le_bytes([buf[1], buf[2], buf[3], buf[4]]);
            let y = i32::from_le_bytes([buf[5], buf[6], buf[7], buf[8]]);
            Some(Event::MouseRightUp { x, y })
        }
        7 => {
            let x = i32::from_le_bytes([buf[1], buf[2], buf[3], buf[4]]);
            let y = i32::from_le_bytes([buf[5], buf[6], buf[7], buf[8]]);
            Some(Event::MouseMove { x, y })
        }
        8 => Some(Event::ScrollUp),
        9 => Some(Event::ScrollDown),
        _ => None,
    }
}