From 509e5ce1e17417a70b9bcce8bc6e33c05106811d Mon Sep 17 00:00:00 2001 From: Mica White Date: Thu, 15 Aug 2024 20:23:26 -0400 Subject: Start profiling --- .cargo/Config.toml | 32 +- .gitignore | 6 +- .vscode/settings.json | 124 +++---- Cargo.toml | 5 +- alligator_backend.lib | Bin 0 -> 625152 bytes book/src/performance.md | 20 +- console/src/lib.rs | 43 ++- deny.toml | 12 +- game.json | 40 +-- profiler/Cargo.toml | 10 + profiler/src/lib.rs | 103 ++++++ rustfmt.toml | 4 +- scripts/Cargo.toml | 2 +- scripts/bin/benchmark.rs | 32 +- scripts/bin/ex.wat | 58 ++-- scripts/src/libs/allocate.rs | 152 ++++----- scripts/src/libs/buffer.rs | 364 ++++++++++---------- scripts/src/libs/ctype.rs | 170 ++++----- scripts/src/libs/math.rs | 796 +++++++++++++++++++++---------------------- scripts/src/libs/mod.rs | 38 +-- scripts/src/libs/system.rs | 308 ++++++++--------- scripts/src/vtable.rs | 20 +- scripts/src/wasm.rs | 340 +++++++++--------- shell-spec.txt | 29 +- src/main.rs | 299 ++++++++-------- sys/alligator_backend.lib | Bin 0 -> 625152 bytes sys/build.rs | 16 +- sys/src/renderer.rs | 98 +++--- sys/src/window.rs | 232 ++++++------- todos.txt | 4 +- 30 files changed, 1761 insertions(+), 1596 deletions(-) create mode 100644 alligator_backend.lib create mode 100644 profiler/Cargo.toml create mode 100644 profiler/src/lib.rs create mode 100644 sys/alligator_backend.lib diff --git a/.cargo/Config.toml b/.cargo/Config.toml index 32e1bdc..df202b6 100644 --- a/.cargo/Config.toml +++ b/.cargo/Config.toml @@ -1,16 +1,16 @@ -[profile.small] -opt-level = "z" -inherits = "release" - -[profile.bm] -lto = true -inherits = "dev" - -[profile.release] -lto = true -strip = true -codegen-units = 1 -panic = "abort" - -[profile.dev] -opt-level = 1 +[profile.small] +opt-level = "z" +inherits = "release" + +[profile.bm] +lto = true +inherits = "dev" + +[profile.release] +lto = true +strip = true +codegen-units = 1 +panic = "abort" + +[profile.dev] +opt-level = 1 diff --git a/.gitignore b/.gitignore index bbbe8bb..0c4f2d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/target -/Cargo.lock -*/target +/target +/Cargo.lock +*/target */Cargo.lock \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index c2985e2..6da577e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,63 +1,63 @@ -{ - "files.associations": { - "algorithm": "cpp", - "atomic": "cpp", - "bit": "cpp", - "cctype": "cpp", - "charconv": "cpp", - "chrono": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "compare": "cpp", - "concepts": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "exception": "cpp", - "format": "cpp", - "forward_list": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "ios": "cpp", - "iosfwd": "cpp", - "istream": "cpp", - "iterator": "cpp", - "limits": "cpp", - "locale": "cpp", - "map": "cpp", - "memory": "cpp", - "new": "cpp", - "optional": "cpp", - "ostream": "cpp", - "ratio": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "string": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "typeinfo": "cpp", - "utility": "cpp", - "vector": "cpp", - "xfacet": "cpp", - "xiosbase": "cpp", - "xlocale": "cpp", - "xlocbuf": "cpp", - "xlocinfo": "cpp", - "xlocmes": "cpp", - "xlocmon": "cpp", - "xlocnum": "cpp", - "xloctime": "cpp", - "xmemory": "cpp", - "xstddef": "cpp", - "xstring": "cpp", - "xtr1common": "cpp", - "xtree": "cpp", - "xutility": "cpp" - } +{ + "files.associations": { + "algorithm": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "exception": "cpp", + "format": "cpp", + "forward_list": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "locale": "cpp", + "map": "cpp", + "memory": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "ratio": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "utility": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstddef": "cpp", + "xstring": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp" + } } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 9a0015a..49cf229 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["scripts", "sprites", "sys", "console"] +members = ["scripts", "sprites", "sys", "console", "profiler"] resolver = "2" [package] @@ -10,6 +10,8 @@ rust-version = "1.65" publish = false [dependencies] +alligator_console = { path = "console" } +alligator_profiler = { path = "profiler" } alligator_scripts = { path = "scripts" } alligator_sprites = { path = "sprites" } alligator_sys = { path = "sys" } @@ -17,6 +19,7 @@ alligator_sys = { path = "sys" } clap = "4" serde = "1" serde_json = "1" +pollster = "0.3" sha3 = "0.10" [profile.release] diff --git a/alligator_backend.lib b/alligator_backend.lib new file mode 100644 index 0000000..1b79670 Binary files /dev/null and b/alligator_backend.lib differ diff --git a/book/src/performance.md b/book/src/performance.md index d769a6f..e97d0ef 100644 --- a/book/src/performance.md +++ b/book/src/performance.md @@ -1,10 +1,10 @@ -# Performance - -Here are some tips to make your game perform more quickly - -## Scripts - -Generally, one large WebAssembly script will perform better than many small -scripts. There is overhead that comes from calling a script, and more scripts -will result in more overhead. Try to have as few scripts as possible. Ideally, -you should have no more than 20 scripts enabled at the same time. +# Performance + +Here are some tips to make your game perform more quickly + +## Scripts + +Generally, one large WebAssembly script will perform better than many small +scripts. There is overhead that comes from calling a script, and more scripts +will result in more overhead. Try to have as few scripts as possible. Ideally, +you should have no more than 20 scripts enabled at the same time. diff --git a/console/src/lib.rs b/console/src/lib.rs index afab4af..d98183c 100644 --- a/console/src/lib.rs +++ b/console/src/lib.rs @@ -12,6 +12,8 @@ pub struct Console { sender: Sender, } +pub struct ConsoleLogger(Sender); + pub enum ConsoleMessage { RuntimeLog { message: String, @@ -25,10 +27,18 @@ pub enum ConsoleMessage { file: String, line: u32, }, + FrameTime { + timestamp: i64, + }, + ScopeStart { + scope_name: String, + timestamp: i64, + }, + ScopeEnd { + timestamp: i64, + }, } -pub struct ConsoleLogger(Sender); - impl Console { pub async fn new(port: u16) -> Result { let tcp_listener = TcpListener::bind((Ipv6Addr::LOCALHOST, port)).await?; @@ -41,7 +51,7 @@ impl Console { }) } - pub fn sender(&self) -> Sender { + fn sender(&self) -> Sender { self.sender.clone() } @@ -58,6 +68,7 @@ impl Console { file, line, } => { + let message = message.replace('\n', "\\n"); let msg = format!("runtimelog {level} {file}:{line} {message}\n"); self.tcp_socket.write(msg.as_bytes()).await?; } @@ -67,9 +78,29 @@ impl Console { file, line, } => { + let message = message.replace('\n', "\\n"); let msg = format!("scriptlog {level} {file}:{line} {message}\n"); self.tcp_socket.write(msg.as_bytes()).await?; } + ConsoleMessage::FrameTime { + timestamp: unix_timestamp, + } => { + let msg = format!("frametime {unix_timestamp}"); + self.tcp_socket.write(msg.as_bytes()).await?; + } + ConsoleMessage::ScopeStart { + scope_name, + timestamp: unix_timestamp, + } => { + let msg = format!("scopestart {scope_name} {unix_timestamp}"); + self.tcp_socket.write(msg.as_bytes()).await?; + } + ConsoleMessage::ScopeEnd { + timestamp: unix_timestamp, + } => { + let msg = format!("scopeend {unix_timestamp}"); + self.tcp_socket.write(msg.as_bytes()).await?; + } } } @@ -79,6 +110,12 @@ impl Console { } } +impl ConsoleLogger { + pub fn send(&self, message: ConsoleMessage) { + _ = self.0.send(message).block_on(); + } +} + impl log::Log for ConsoleLogger { fn enabled(&self, _: &log::Metadata) -> bool { true diff --git a/deny.toml b/deny.toml index 59a150b..c387c36 100644 --- a/deny.toml +++ b/deny.toml @@ -1,7 +1,7 @@ -[licenses] -allow = ["MIT", "Zlib", "Unlicense"] -default = "allow" -copyleft = "deny" - -[licenses.private] +[licenses] +allow = ["MIT", "Zlib", "Unlicense"] +default = "allow" +copyleft = "deny" + +[licenses.private] ignore = true \ No newline at end of file diff --git a/game.json b/game.json index 9014385..479c8f1 100644 --- a/game.json +++ b/game.json @@ -1,21 +1,21 @@ -{ - "alligator_version": 0, - "scenes": { - "black": { - "initial_sprites": {}, - "initial_scripts": [] - } - }, - "textures": {}, - "scripts": {}, - "default_scene": "black", - "default_textures_size_target": 0, - "sprite_manager_capacity": 0, - "default_window_width": 640, - "default_window_height": 480, - "default_atlas_width": 640, - "default_atlas_height": 480, - "default_window_mode": "Windowed", - "window_title": "Black.exe", - "vsync": true +{ + "alligator_version": 0, + "scenes": { + "black": { + "initial_sprites": {}, + "initial_scripts": [] + } + }, + "textures": {}, + "scripts": {}, + "default_scene": "black", + "default_textures_size_target": 0, + "sprite_manager_capacity": 0, + "default_window_width": 640, + "default_window_height": 480, + "default_atlas_width": 640, + "default_atlas_height": 480, + "default_window_mode": "Windowed", + "window_title": "Black.exe", + "vsync": true } \ No newline at end of file diff --git a/profiler/Cargo.toml b/profiler/Cargo.toml new file mode 100644 index 0000000..d9c7f2b --- /dev/null +++ b/profiler/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "alligator_profiler" +version = "0.1.0" +edition = "2021" + +[dependencies] +alligator_console = { path = "../console" } + +scopeguard = "1" +chrono = "0.4" \ No newline at end of file diff --git a/profiler/src/lib.rs b/profiler/src/lib.rs new file mode 100644 index 0000000..d23ad24 --- /dev/null +++ b/profiler/src/lib.rs @@ -0,0 +1,103 @@ +use std::sync::OnceLock; + +use alligator_console::{ConsoleLogger, ConsoleMessage}; +use chrono::{DateTime, Utc}; +use scopeguard::ScopeGuard; + +static GLOBAL_PROFILER: OnceLock = OnceLock::new(); + +struct Profiler { + logger: ConsoleLogger, + start_time: DateTime, +} + +impl Profiler { + fn new(logger: ConsoleLogger) -> Self { + Self { + logger, + start_time: Utc::now(), + } + } + + fn current_timestamp(&self) -> i64 { + Utc::now() + .signed_duration_since(DateTime::UNIX_EPOCH) + .num_microseconds() + .unwrap_or(i64::MAX) + } + + fn finish_frame(&self) { + self.logger.send(ConsoleMessage::FrameTime { + timestamp: self.current_timestamp(), + }) + } + + fn start_scope(&self, scope_name: String) { + self.logger.send(ConsoleMessage::ScopeStart { + scope_name, + timestamp: self.current_timestamp(), + }) + } + + fn end_scope(&self) { + self.logger.send(ConsoleMessage::ScopeEnd { + timestamp: self.current_timestamp(), + }) + } +} + +pub fn set_profiler(logger: ConsoleLogger) { + GLOBAL_PROFILER.get_or_init(|| Profiler::new(logger)); +} + +pub fn finish_frame() { + GLOBAL_PROFILER.get().unwrap().finish_frame(); +} + +pub fn start_scope(scope_name: impl AsRef) { + GLOBAL_PROFILER + .get() + .unwrap() + .start_scope(scope_name.as_ref().to_string()); +} + +pub fn end_scope() { + GLOBAL_PROFILER.get().unwrap().end_scope(); +} + +pub fn profile_scope(scope_name: impl AsRef) -> ScopeGuard<(), impl FnOnce(())> { + start_scope(scope_name); + scopeguard::guard((), |_| end_scope()) +} + +#[macro_export] +macro_rules! scope { + ($scope_name: expr) => { + let _profiling_scope = $crate::profile_scope($scope_name); + }; + () => { + let _profiling_scope = $crate::profile_scope("unnamed scope"); + }; +} + +#[macro_export] +macro_rules! function_name { + () => {{ + fn f() {} + fn type_name_of(_: T) -> &'static str { + std::any::type_name::() + } + type_name_of(f) + .split("::") + .filter(|&part| part != "f") + .collect::>() + .join("::") + }}; +} + +#[macro_export] +macro_rules! profile_function { + () => { + $crate::scope!($crate::function_name!()); + }; +} diff --git a/rustfmt.toml b/rustfmt.toml index 2508efc..bf5ad5c 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,3 @@ -edition = "2021" -newline_style = "Unix" +edition = "2021" +newline_style = "Unix" hard_tabs = true \ No newline at end of file diff --git a/scripts/Cargo.toml b/scripts/Cargo.toml index 88aa2c7..a9fe5e4 100644 --- a/scripts/Cargo.toml +++ b/scripts/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -wasmtime = "14" +wasmtime = "15" rayon = "1" thiserror = "1" rand = "0.8" diff --git a/scripts/bin/benchmark.rs b/scripts/bin/benchmark.rs index 24f672d..681bace 100644 --- a/scripts/bin/benchmark.rs +++ b/scripts/bin/benchmark.rs @@ -1,16 +1,16 @@ -use std::time::Instant; - -use scripts::ScriptManager; - -fn main() { - let mut manager = ScriptManager::new(); - let start = Instant::now(); - manager - .add_wasm_script(Box::from("example"), "bin/ex.wat", false) - .unwrap(); - println!("Took {} microseconds", start.elapsed().as_micros()); - - let start = Instant::now(); - manager.run_update_scripts(); - println!("Took {} microseconds", start.elapsed().as_micros()); -} +use std::time::Instant; + +use scripts::ScriptManager; + +fn main() { + let mut manager = ScriptManager::new(); + let start = Instant::now(); + manager + .add_wasm_script(Box::from("example"), "bin/ex.wat", false) + .unwrap(); + println!("Took {} microseconds", start.elapsed().as_micros()); + + let start = Instant::now(); + manager.run_update_scripts(); + println!("Took {} microseconds", start.elapsed().as_micros()); +} diff --git a/scripts/bin/ex.wat b/scripts/bin/ex.wat index af461bd..3f8e609 100644 --- a/scripts/bin/ex.wat +++ b/scripts/bin/ex.wat @@ -1,29 +1,29 @@ -(module - (import "alligator" "abs" (func $abs (param i32) (result i32))) - (func $add1 - (local $i i32) - (loop $myloop - local.get $i - i32.const 1 - i32.add - local.set $i - - local.get $i - call $abs - - local.get $i - i32.const 40 - i32.lt_s - br_if $myloop - - drop - ) - ) - (func $add2 nop) - (export "begin" (func $add2)) - (export "update" (func $add1)) - (memory (;0;) 16) - (export "memory" (memory 0)) - (global $base i32 (i32.const 1)) - (export "__heap_base" (global $base)) -) +(module + (import "alligator" "abs" (func $abs (param i32) (result i32))) + (func $add1 + (local $i i32) + (loop $myloop + local.get $i + i32.const 1 + i32.add + local.set $i + + local.get $i + call $abs + + local.get $i + i32.const 40 + i32.lt_s + br_if $myloop + + drop + ) + ) + (func $add2 nop) + (export "begin" (func $add2)) + (export "update" (func $add1)) + (memory (;0;) 16) + (export "memory" (memory 0)) + (global $base i32 (i32.const 1)) + (export "__heap_base" (global $base)) +) diff --git a/scripts/src/libs/allocate.rs b/scripts/src/libs/allocate.rs index 7f2825d..c2bb2cf 100644 --- a/scripts/src/libs/allocate.rs +++ b/scripts/src/libs/allocate.rs @@ -1,76 +1,76 @@ -use wasmtime::Caller; - -use crate::{ScriptManager, WasmScriptState}; - -use super::{ - system::{_alloc, _get_memory}, - LIBRARY_NAME, -}; - -fn allocate_zeroed(mut caller: Caller<'_, WasmScriptState>, size: u32, align: u32) -> u32 { - let Some((ptr, data)) = _alloc(&mut caller, size, align) else { - return 0; - }; - - data.fill(0); - ptr -} - -fn reallocate( - mut caller: Caller<'_, WasmScriptState>, - ptr: u32, - size: u32, - new_size: u32, - align: u32, -) -> u32 { - if new_size < size { - return ptr; - } - - let bump_pointer = &mut caller.data_mut().bump_pointer; - if *bump_pointer == ptr + size { - *bump_pointer = ptr; - let Some((new_ptr, _)) = _alloc(&mut caller, new_size, align) else { - return 4; - }; - return new_ptr; - } - - let (_, original) = _get_memory(&mut caller); - let Some(original) = original.get(ptr as usize..(ptr + size) as usize) else { - return 4; - }; - let original = original.to_vec(); - - let Some((new_ptr, data)) = _alloc(&mut caller, new_size, align) else { - return 0; - }; - - data.get_mut(..size as usize) - .unwrap() - .clone_from_slice(&original); - new_ptr -} - -fn duplicate(mut caller: Caller<'_, WasmScriptState>, ptr: u32, size: u32, align: u32) -> u32 { - let (_, original) = _get_memory(&mut caller); - let Some(original) = original.get(ptr as usize..(ptr + size) as usize) else { - return 4; - }; - let original = original.to_vec(); - - let Some((new_ptr, data)) = _alloc(&mut caller, size, align) else { - return 0; - }; - - data.clone_from_slice(&original); - new_ptr -} - -pub fn library(manager: &mut ScriptManager) -> Option<()> { - manager.add_library_function(LIBRARY_NAME, "calloc", allocate_zeroed)?; - manager.add_library_function(LIBRARY_NAME, "realloc", reallocate)?; - manager.add_library_function(LIBRARY_NAME, "memdup", duplicate)?; - - Some(()) -} +use wasmtime::Caller; + +use crate::{ScriptManager, WasmScriptState}; + +use super::{ + system::{_alloc, _get_memory}, + LIBRARY_NAME, +}; + +fn allocate_zeroed(mut caller: Caller<'_, WasmScriptState>, size: u32, align: u32) -> u32 { + let Some((ptr, data)) = _alloc(&mut caller, size, align) else { + return 0; + }; + + data.fill(0); + ptr +} + +fn reallocate( + mut caller: Caller<'_, WasmScriptState>, + ptr: u32, + size: u32, + new_size: u32, + align: u32, +) -> u32 { + if new_size < size { + return ptr; + } + + let bump_pointer = &mut caller.data_mut().bump_pointer; + if *bump_pointer == ptr + size { + *bump_pointer = ptr; + let Some((new_ptr, _)) = _alloc(&mut caller, new_size, align) else { + return 4; + }; + return new_ptr; + } + + let (_, original) = _get_memory(&mut caller); + let Some(original) = original.get(ptr as usize..(ptr + size) as usize) else { + return 4; + }; + let original = original.to_vec(); + + let Some((new_ptr, data)) = _alloc(&mut caller, new_size, align) else { + return 0; + }; + + data.get_mut(..size as usize) + .unwrap() + .clone_from_slice(&original); + new_ptr +} + +fn duplicate(mut caller: Caller<'_, WasmScriptState>, ptr: u32, size: u32, align: u32) -> u32 { + let (_, original) = _get_memory(&mut caller); + let Some(original) = original.get(ptr as usize..(ptr + size) as usize) else { + return 4; + }; + let original = original.to_vec(); + + let Some((new_ptr, data)) = _alloc(&mut caller, size, align) else { + return 0; + }; + + data.clone_from_slice(&original); + new_ptr +} + +pub fn library(manager: &mut ScriptManager) -> Option<()> { + manager.add_library_function(LIBRARY_NAME, "calloc", allocate_zeroed)?; + manager.add_library_function(LIBRARY_NAME, "realloc", reallocate)?; + manager.add_library_function(LIBRARY_NAME, "memdup", duplicate)?; + + Some(()) +} diff --git a/scripts/src/libs/buffer.rs b/scripts/src/libs/buffer.rs index b4cee77..0958260 100644 --- a/scripts/src/libs/buffer.rs +++ b/scripts/src/libs/buffer.rs @@ -1,182 +1,182 @@ -use wasmtime::Caller; - -use crate::{ScriptManager, WasmScriptState}; - -use super::{system::_get_memory, LIBRARY_NAME}; - -fn memory_search(mut caller: Caller<'_, WasmScriptState>, ptr: u32, ch: u32, len: u32) -> u32 { - let (_, mem_ptr) = _get_memory(&mut caller); - let len = len as usize; - let ptr = ptr as usize; - let ch = ch as u8; - if (len + ptr) > mem_ptr.len() { - return 4; - } - - for i in 0..len { - if mem_ptr[ptr + i] == ch { - return (ptr + i) as u32; - } - } - - 0 -} - -fn memory_search_last(mut caller: Caller<'_, WasmScriptState>, ptr: u32, ch: u32, len: u32) -> u32 { - let (_, mem_ptr) = _get_memory(&mut caller); - let len = len as usize; - let ptr = ptr as usize; - let ch = ch as u8; - if (len + ptr) > mem_ptr.len() { - return 4; - } - - for i in 0..len { - let index = ptr + len - i - 1; - if mem_ptr[index] == ch { - return index as u32; - } - } - - 0 -} - -fn memory_compare( - mut caller: Caller<'_, WasmScriptState>, - lhs: u32, - rhs: u32, - len: u32, -) -> (u32, u32) { - let (_, mem_ptr) = _get_memory(&mut caller); - let len = len as usize; - let lhs = lhs as usize; - let rhs = rhs as usize; - if (len + lhs) > mem_ptr.len() || (len + rhs) > mem_ptr.len() { - return (4, 0); - } - - for i in 0..len { - let diff = mem_ptr[lhs + i] - mem_ptr[rhs + i]; - if diff != 0 { - return (0, diff as u32); - } - } - - (0, 0) -} - -fn memory_fill(mut caller: Caller<'_, WasmScriptState>, dest: u32, ch: u32, len: u32) -> u32 { - let (_, mem_ptr) = _get_memory(&mut caller); - let len = len as usize; - let dest = dest as usize; - let ch = ch as u8; - - if (len + dest) > mem_ptr.len() { - return 4; - } - - for i in 0..len { - mem_ptr[dest + i] = ch; - } - - 0 -} - -fn memory_copy(mut caller: Caller<'_, WasmScriptState>, dest: u32, src: u32, len: u32) -> u32 { - let (_, mem_ptr) = _get_memory(&mut caller); - let len = len as usize; - let dest = dest as usize; - let src = src as usize; - if (len + dest) > mem_ptr.len() || (len + src) > mem_ptr.len() { - return 4; - } - - // check for overlap - if (dest < src && dest + len > src) || (src < dest && src + len > dest) { - let src = mem_ptr[src..src + len].to_vec(); - let dest = &mut mem_ptr[dest..dest + len]; - dest.clone_from_slice(&src); - } else { - for i in 0..len { - mem_ptr[dest + i] = mem_ptr[src + i]; - } - } - - 0 -} - -fn memory_copy_until( - mut caller: Caller<'_, WasmScriptState>, - dest: u32, - src: u32, - len: u32, - delimiter: u32, -) -> u32 { - let (_, mem_ptr) = _get_memory(&mut caller); - let len = len as usize; - let dest = dest as usize; - let src = src as usize; - let delimiter = delimiter as u8; - if (len + dest) > mem_ptr.len() || (len + src) > mem_ptr.len() { - return 4; - } - - // check for overlap - if (dest < src && dest + len > src) || (src < dest && src + len > dest) { - let cloned_src = mem_ptr[src..src + len].to_vec(); - let dest = &mut mem_ptr[dest..dest + len]; - for i in 0..len { - let ch = cloned_src[i]; - dest[i] = ch; - if ch == delimiter { - return (src + i + 1) as u32; - } - } - } else { - for i in 0..len { - let ch = mem_ptr[src + i]; - mem_ptr[dest + i] = ch; - if ch == delimiter { - return (src + i + 1) as u32; - } - } - } - - 0 -} - -fn memory_concatenate( - mut caller: Caller<'_, WasmScriptState>, - dest: u32, - src: u32, - dest_len: u32, - src_len: u32, -) -> u32 { - let (_, mem_ptr) = _get_memory(&mut caller); - let dest = dest as usize; - let src = src as usize; - let dest_len = dest_len as usize; - let src_len = src_len as usize; - if (dest_len + src_len + dest) > mem_ptr.len() || (src_len + src) > mem_ptr.len() { - return 4; - } - - let src = mem_ptr[src..src + src_len].to_vec(); - let dest_offset = dest + dest_len; - let dest = &mut mem_ptr[dest_offset..dest_offset + src_len]; - dest.clone_from_slice(&src); - - 0 -} - -pub fn library(manager: &mut ScriptManager) -> Option<()> { - manager.add_library_function(LIBRARY_NAME, "memchr", memory_search)?; - manager.add_library_function(LIBRARY_NAME, "memrchr", memory_search_last)?; - manager.add_library_function(LIBRARY_NAME, "memcmp", memory_compare)?; - manager.add_library_function(LIBRARY_NAME, "memset", memory_fill)?; - manager.add_library_function(LIBRARY_NAME, "memcpy", memory_copy)?; - manager.add_library_function(LIBRARY_NAME, "memccpy", memory_copy_until)?; - manager.add_library_function(LIBRARY_NAME, "memcat", memory_concatenate)?; - - Some(()) -} +use wasmtime::Caller; + +use crate::{ScriptManager, WasmScriptState}; + +use super::{system::_get_memory, LIBRARY_NAME}; + +fn memory_search(mut caller: Caller<'_, WasmScriptState>, ptr: u32, ch: u32, len: u32) -> u32 { + let (_, mem_ptr) = _get_memory(&mut caller); + let len = len as usize; + let ptr = ptr as usize; + let ch = ch as u8; + if (len + ptr) > mem_ptr.len() { + return 4; + } + + for i in 0..len { + if mem_ptr[ptr + i] == ch { + return (ptr + i) as u32; + } + } + + 0 +} + +fn memory_search_last(mut caller: Caller<'_, WasmScriptState>, ptr: u32, ch: u32, len: u32) -> u32 { + let (_, mem_ptr) = _get_memory(&mut caller); + let len = len as usize; + let ptr = ptr as usize; + let ch = ch as u8; + if (len + ptr) > mem_ptr.len() { + return 4; + } + + for i in 0..len { + let index = ptr + len - i - 1; + if mem_ptr[index] == ch { + return index as u32; + } + } + + 0 +} + +fn memory_compare( + mut caller: Caller<'_, WasmScriptState>, + lhs: u32, + rhs: u32, + len: u32, +) -> (u32, u32) { + let (_, mem_ptr) = _get_memory(&mut caller); + let len = len as usize; + let lhs = lhs as usize; + let rhs = rhs as usize; + if (len + lhs) > mem_ptr.len() || (len + rhs) > mem_ptr.len() { + return (4, 0); + } + + for i in 0..len { + let diff = mem_ptr[lhs + i] - mem_ptr[rhs + i]; + if diff != 0 { + return (0, diff as u32); + } + } + + (0, 0) +} + +fn memory_fill(mut caller: Caller<'_, WasmScriptState>, dest: u32, ch: u32, len: u32) -> u32 { + let (_, mem_ptr) = _get_memory(&mut caller); + let len = len as usize; + let dest = dest as usize; + let ch = ch as u8; + + if (len + dest) > mem_ptr.len() { + return 4; + } + + for i in 0..len { + mem_ptr[dest + i] = ch; + } + + 0 +} + +fn memory_copy(mut caller: Caller<'_, WasmScriptState>, dest: u32, src: u32, len: u32) -> u32 { + let (_, mem_ptr) = _get_memory(&mut caller); + let len = len as usize; + let dest = dest as usize; + let src = src as usize; + if (len + dest) > mem_ptr.len() || (len + src) > mem_ptr.len() { + return 4; + } + + // check for overlap + if (dest < src && dest + len > src) || (src < dest && src + len > dest) { + let src = mem_ptr[src..src + len].to_vec(); + let dest = &mut mem_ptr[dest..dest + len]; + dest.clone_from_slice(&src); + } else { + for i in 0..len { + mem_ptr[dest + i] = mem_ptr[src + i]; + } + } + + 0 +} + +fn memory_copy_until( + mut caller: Caller<'_, WasmScriptState>, + dest: u32, + src: u32, + len: u32, + delimiter: u32, +) -> u32 { + let (_, mem_ptr) = _get_memory(&mut caller); + let len = len as usize; + let dest = dest as usize; + let src = src as usize; + let delimiter = delimiter as u8; + if (len + dest) > mem_ptr.len() || (len + src) > mem_ptr.len() { + return 4; + } + + // check for overlap + if (dest < src && dest + len > src) || (src < dest && src + len > dest) { + let cloned_src = mem_ptr[src..src + len].to_vec(); + let dest = &mut mem_ptr[dest..dest + len]; + for i in 0..len { + let ch = cloned_src[i]; + dest[i] = ch; + if ch == delimiter { + return (src + i + 1) as u32; + } + } + } else { + for i in 0..len { + let ch = mem_ptr[src + i]; + mem_ptr[dest + i] = ch; + if ch == delimiter { + return (src + i + 1) as u32; + } + } + } + + 0 +} + +fn memory_concatenate( + mut caller: Caller<'_, WasmScriptState>, + dest: u32, + src: u32, + dest_len: u32, + src_len: u32, +) -> u32 { + let (_, mem_ptr) = _get_memory(&mut caller); + let dest = dest as usize; + let src = src as usize; + let dest_len = dest_len as usize; + let src_len = src_len as usize; + if (dest_len + src_len + dest) > mem_ptr.len() || (src_len + src) > mem_ptr.len() { + return 4; + } + + let src = mem_ptr[src..src + src_len].to_vec(); + let dest_offset = dest + dest_len; + let dest = &mut mem_ptr[dest_offset..dest_offset + src_len]; + dest.clone_from_slice(&src); + + 0 +} + +pub fn library(manager: &mut ScriptManager) -> Option<()> { + manager.add_library_function(LIBRARY_NAME, "memchr", memory_search)?; + manager.add_library_function(LIBRARY_NAME, "memrchr", memory_search_last)?; + manager.add_library_function(LIBRARY_NAME, "memcmp", memory_compare)?; + manager.add_library_function(LIBRARY_NAME, "memset", memory_fill)?; + manager.add_library_function(LIBRARY_NAME, "memcpy", memory_copy)?; + manager.add_library_function(LIBRARY_NAME, "memccpy", memory_copy_until)?; + manager.add_library_function(LIBRARY_NAME, "memcat", memory_concatenate)?; + + Some(()) +} diff --git a/scripts/src/libs/ctype.rs b/scripts/src/libs/ctype.rs index ca4f326..1236936 100644 --- a/scripts/src/libs/ctype.rs +++ b/scripts/src/libs/ctype.rs @@ -1,85 +1,85 @@ -use crate::{libs::LIBRARY_NAME, ScriptManager}; - -fn char_is(func: impl Fn(char) -> bool, ch: u32) -> u32 { - let Some(ch) = char::from_u32(ch) else { - return 0; - }; - - func(ch) as u32 -} - -macro_rules! ctype { - (fn $fn_name: ident => $fn: expr;) => { - fn $fn_name(ch: u32) -> u32 { - char_is($fn, ch) - } - }; - (fn $fn_name: ident => $fn: expr; $(fn $fn_name2: ident => $fn2: expr;)*) => { - fn $fn_name(ch: u32) -> u32 { - char_is($fn, ch) - } - ctype!($(fn $fn_name2 => $fn2;)*); - }; -} - -ctype!( - fn is_alphanumeric => |ch| ch.is_alphanumeric(); - fn is_alphabetic => |ch| ch.is_alphabetic(); - fn is_lowercase => |ch| ch.is_lowercase(); - fn is_uppercase => |ch| ch.is_uppercase(); - fn is_control => |ch| ch.is_control(); - fn is_whitespace => |ch| ch.is_whitespace(); - fn is_ascii_alphanumeric => |ch| ch.is_ascii_alphanumeric(); - fn is_ascii_alphabetic => |ch| ch.is_ascii_alphabetic(); - fn is_ascii_lowercase => |ch| ch.is_ascii_lowercase(); - fn is_ascii_uppercase => |ch| ch.is_ascii_lowercase(); - fn is_ascii_digit => |ch| ch.is_ascii_digit(); - fn is_ascii_hexdigit => |ch| ch.is_ascii_hexdigit(); - fn is_ascii_control => |ch| ch.is_ascii_control(); - fn is_ascii_graphical => |ch| ch.is_ascii_graphic(); - fn is_ascii_whitespace => |ch| ch.is_ascii_whitespace(); - fn is_ascii_blank => |ch| ch == ' ' || ch == '\t'; - fn is_ascii_printable => |ch| ch.is_alphanumeric() || ch.is_ascii_punctuation(); - fn is_ascii_punctuation => |ch| ch.is_ascii_punctuation(); -); - -fn to_ascii_lower(ch: u32) -> u32 { - let Some(ch) = char::from_u32(ch) else { - return ch; - }; - - ch.to_ascii_lowercase() as u32 -} - -fn to_ascii_upper(ch: u32) -> u32 { - let Some(ch) = char::from_u32(ch) else { - return ch; - }; - - ch.to_ascii_uppercase() as u32 -} - -pub fn library(manager: &mut ScriptManager) -> Option<()> { - manager.add_library_function(LIBRARY_NAME, "iswalnum", is_alphanumeric)?; - manager.add_library_function(LIBRARY_NAME, "iswalpha", is_alphabetic)?; - manager.add_library_function(LIBRARY_NAME, "iswlower", is_lowercase)?; - manager.add_library_function(LIBRARY_NAME, "iswupper", is_uppercase)?; - manager.add_library_function(LIBRARY_NAME, "iswcntrl", is_control)?; - manager.add_library_function(LIBRARY_NAME, "iswspace", is_whitespace)?; - manager.add_library_function(LIBRARY_NAME, "isalnum", is_ascii_alphanumeric)?; - manager.add_library_function(LIBRARY_NAME, "isalpha", is_ascii_alphabetic)?; - manager.add_library_function(LIBRARY_NAME, "islower", is_ascii_lowercase)?; - manager.add_library_function(LIBRARY_NAME, "isupper", is_ascii_uppercase)?; - manager.add_library_function(LIBRARY_NAME, "isdigit", is_ascii_digit)?; - manager.add_library_function(LIBRARY_NAME, "isxdigit", is_ascii_hexdigit)?; - manager.add_library_function(LIBRARY_NAME, "iscntrl", is_ascii_control)?; - manager.add_library_function(LIBRARY_NAME, "isgraph", is_ascii_graphical)?; - manager.add_library_function(LIBRARY_NAME, "isspace", is_ascii_whitespace)?; - manager.add_library_function(LIBRARY_NAME, "isblank", is_ascii_blank)?; - manager.add_library_function(LIBRARY_NAME, "isprint", is_ascii_printable)?; - manager.add_library_function(LIBRARY_NAME, "ispunct", is_ascii_punctuation)?; - manager.add_library_function(LIBRARY_NAME, "tolower", to_ascii_lower)?; - manager.add_library_function(LIBRARY_NAME, "toupper", to_ascii_upper)?; - - Some(()) -} +use crate::{libs::LIBRARY_NAME, ScriptManager}; + +fn char_is(func: impl Fn(char) -> bool, ch: u32) -> u32 { + let Some(ch) = char::from_u32(ch) else { + return 0; + }; + + func(ch) as u32 +} + +macro_rules! ctype { + (fn $fn_name: ident => $fn: expr;) => { + fn $fn_name(ch: u32) -> u32 { + char_is($fn, ch) + } + }; + (fn $fn_name: ident => $fn: expr; $(fn $fn_name2: ident => $fn2: expr;)*) => { + fn $fn_name(ch: u32) -> u32 { + char_is($fn, ch) + } + ctype!($(fn $fn_name2 => $fn2;)*); + }; +} + +ctype!( + fn is_alphanumeric => |ch| ch.is_alphanumeric(); + fn is_alphabetic => |ch| ch.is_alphabetic(); + fn is_lowercase => |ch| ch.is_lowercase(); + fn is_uppercase => |ch| ch.is_uppercase(); + fn is_control => |ch| ch.is_control(); + fn is_whitespace => |ch| ch.is_whitespace(); + fn is_ascii_alphanumeric => |ch| ch.is_ascii_alphanumeric(); + fn is_ascii_alphabetic => |ch| ch.is_ascii_alphabetic(); + fn is_ascii_lowercase => |ch| ch.is_ascii_lowercase(); + fn is_ascii_uppercase => |ch| ch.is_ascii_lowercase(); + fn is_ascii_digit => |ch| ch.is_ascii_digit(); + fn is_ascii_hexdigit => |ch| ch.is_ascii_hexdigit(); + fn is_ascii_control => |ch| ch.is_ascii_control(); + fn is_ascii_graphical => |ch| ch.is_ascii_graphic(); + fn is_ascii_whitespace => |ch| ch.is_ascii_whitespace(); + fn is_ascii_blank => |ch| ch == ' ' || ch == '\t'; + fn is_ascii_printable => |ch| ch.is_alphanumeric() || ch.is_ascii_punctuation(); + fn is_ascii_punctuation => |ch| ch.is_ascii_punctuation(); +); + +fn to_ascii_lower(ch: u32) -> u32 { + let Some(ch) = char::from_u32(ch) else { + return ch; + }; + + ch.to_ascii_lowercase() as u32 +} + +fn to_ascii_upper(ch: u32) -> u32 { + let Some(ch) = char::from_u32(ch) else { + return ch; + }; + + ch.to_ascii_uppercase() as u32 +} + +pub fn library(manager: &mut ScriptManager) -> Option<()> { + manager.add_library_function(LIBRARY_NAME, "iswalnum", is_alphanumeric)?; + manager.add_library_function(LIBRARY_NAME, "iswalpha", is_alphabetic)?; + manager.add_library_function(LIBRARY_NAME, "iswlower", is_lowercase)?; + manager.add_library_function(LIBRARY_NAME, "iswupper", is_uppercase)?; + manager.add_library_function(LIBRARY_NAME, "iswcntrl", is_control)?; + manager.add_library_function(LIBRARY_NAME, "iswspace", is_whitespace)?; + manager.add_library_function(LIBRARY_NAME, "isalnum", is_ascii_alphanumeric)?; + manager.add_library_function(LIBRARY_NAME, "isalpha", is_ascii_alphabetic)?; + manager.add_library_function(LIBRARY_NAME, "islower", is_ascii_lowercase)?; + manager.add_library_function(LIBRARY_NAME, "isupper", is_ascii_uppercase)?; + manager.add_library_function(LIBRARY_NAME, "isdigit", is_ascii_digit)?; + manager.add_library_function(LIBRARY_NAME, "isxdigit", is_ascii_hexdigit)?; + manager.add_library_function(LIBRARY_NAME, "iscntrl", is_ascii_control)?; + manager.add_library_function(LIBRARY_NAME, "isgraph", is_ascii_graphical)?; + manager.add_library_function(LIBRARY_NAME, "isspace", is_ascii_whitespace)?; + manager.add_library_function(LIBRARY_NAME, "isblank", is_ascii_blank)?; + manager.add_library_function(LIBRARY_NAME, "isprint", is_ascii_printable)?; + manager.add_library_function(LIBRARY_NAME, "ispunct", is_ascii_punctuation)?; + manager.add_library_function(LIBRARY_NAME, "tolower", to_ascii_lower)?; + manager.add_library_function(LIBRARY_NAME, "toupper", to_ascii_upper)?; + + Some(()) +} diff --git a/scripts/src/libs/math.rs b/scripts/src/libs/math.rs index 4aae3c3..c20f322 100644 --- a/scripts/src/libs/math.rs +++ b/scripts/src/libs/math.rs @@ -1,398 +1,398 @@ -use crate::ScriptManager; - -use super::LIBRARY_NAME; - -fn abs_i32(n: i32) -> i32 { - n.abs() -} - -fn abs_i64(n: i64) -> i64 { - n.abs() -} - -fn mod_f32(x: f32, y: f32) -> f32 { - libm::fmodf(x, y) -} - -fn mod_f64(x: f64, y: f64) -> f64 { - libm::fmod(x, y) -} - -fn remainder_f32(x: f32, y: f32) -> f32 { - libm::remainderf(x, y) -} - -fn remainder_f64(x: f64, y: f64) -> f64 { - libm::remainder(x, y) -} - -fn mul_add_f32(x: f32, y: f32, z: f32) -> f32 { - x.mul_add(y, z) -} - -fn mul_add_f64(x: f64, y: f64, z: f64) -> f64 { - x.mul_add(y, z) -} - -fn fdim_f32(x: f32, y: f32) -> f32 { - libm::fdimf(x, y) -} - -fn fdim_f64(x: f64, y: f64) -> f64 { - libm::fdim(x, y) -} - -fn exp_f32(x: f32) -> f32 { - x.exp() -} - -fn exp_f64(x: f64) -> f64 { - x.exp() -} - -fn exp2_f32(x: f32) -> f32 { - x.exp2() -} - -fn exp2_f64(x: f64) -> f64 { - x.exp2() -} - -fn expm1_f32(x: f32) -> f32 { - x.exp_m1() -} - -fn expm1_f64(x: f64) -> f64 { - x.exp_m1() -} - -fn ln_f32(x: f32) -> f32 { - x.ln() -} - -fn ln_f64(x: f64) -> f64 { - x.ln() -} - -fn log10_f32(x: f32) -> f32 { - x.log10() -} - -fn log10_f64(x: f64) -> f64 { - x.log10() -} - -fn log2_f32(x: f32) -> f32 { - x.log2() -} - -fn log2_f64(x: f64) -> f64 { - x.log2() -} - -fn ln1p_f32(x: f32) -> f32 { - x.ln_1p() -} - -fn ln1p_f64(x: f64) -> f64 { - x.ln_1p() -} - -fn pow_f32(base: f32, exponent: f32) -> f32 { - base.powf(exponent) -} - -fn pow_f64(base: f64, exponent: f64) -> f64 { - base.powf(exponent) -} - -fn cbrt_f32(x: f32) -> f32 { - x.cbrt() -} - -fn cbrt_f64(x: f64) -> f64 { - x.cbrt() -} - -fn hypotenuse_f32(x: f32, y: f32) -> f32 { - x.hypot(y) -} - -fn hypotenuse_f64(x: f64, y: f64) -> f64 { - x.hypot(y) -} - -fn sin_f32(x: f32) -> f32 { - x.sin() -} - -fn sin_f64(x: f64) -> f64 { - x.sin() -} - -fn cos_f32(x: f32) -> f32 { - x.cos() -} - -fn cos_f64(x: f64) -> f64 { - x.cos() -} - -fn tan_f32(x: f32) -> f32 { - x.tan() -} - -fn tan_f64(x: f64) -> f64 { - x.tan() -} - -fn asin_f32(x: f32) -> f32 { - x.asin() -} - -fn asin_f64(x: f64) -> f64 { - x.asin() -} - -fn acos_f32(x: f32) -> f32 { - x.acos() -} - -fn acos_f64(x: f64) -> f64 { - x.acos() -} - -fn atan_f32(x: f32) -> f32 { - x.atan() -} - -fn atan_f64(x: f64) -> f64 { - x.atan() -} - -fn sinh_f32(x: f32) -> f32 { - x.sinh() -} - -fn sinh_f64(x: f64) -> f64 { - x.sinh() -} - -fn cosh_f32(x: f32) -> f32 { - x.cosh() -} - -fn cosh_f64(x: f64) -> f64 { - x.cosh() -} - -fn tanh_f32(x: f32) -> f32 { - x.tanh() -} - -fn tanh_f64(x: f64) -> f64 { - x.tanh() -} - -fn asinh_f32(x: f32) -> f32 { - x.asinh() -} - -fn asinh_f64(x: f64) -> f64 { - x.asinh() -} - -fn acosh_f32(x: f32) -> f32 { - x.acosh() -} - -fn acosh_f64(x: f64) -> f64 { - x.acosh() -} - -fn atanh_f32(x: f32) -> f32 { - x.atanh() -} - -fn atanh_f64(x: f64) -> f64 { - x.atanh() -} - -fn erf_f32(x: f32) -> f32 { - libm::erff(x) -} - -fn erf_f64(x: f64) -> f64 { - libm::erf(x) -} - -fn erfc_f32(x: f32) -> f32 { - libm::erfcf(x) -} - -fn erfc_f64(x: f64) -> f64 { - libm::erfc(x) -} - -fn gamma_f32(x: f32) -> f32 { - libm::tgammaf(x) -} - -fn gamma_f64(x: f64) -> f64 { - libm::tgamma(x) -} - -fn ln_gamma_f32(x: f32) -> f32 { - libm::lgammaf(x) -} - -fn ln_gamma_f64(x: f64) -> f64 { - libm::lgamma(x) -} - -fn round_f32_i32(x: f32) -> i32 { - x.round() as i32 -} - -fn round_f64_i32(x: f64) -> i32 { - x.round() as i32 -} - -fn round_f32_i64(x: f32) -> i64 { - x.round() as i64 -} - -fn round_f64_i64(x: f64) -> i64 { - x.round() as i64 -} - -fn frexp_f32(x: f32) -> (f32, i32) { - libm::frexpf(x) -} - -fn frexp_f64(x: f64) -> (f64, i32) { - libm::frexp(x) -} - -fn ldexp_f32(x: f32, exp: i32) -> f32 { - libm::ldexpf(x, exp) -} - -fn ldexp_f64(x: f64, exp: i32) -> f64 { - libm::ldexp(x, exp) -} - -fn modf_f32(x: f32) -> (f32, f32) { - libm::modff(x) -} - -fn modf_f64(x: f64) -> (f64, f64) { - libm::modf(x) -} - -fn logb_f32(x: f32) -> i32 { - libm::ilogbf(x) -} - -fn logb_f64(x: f64) -> i32 { - libm::ilogb(x) -} - -fn next_after_f32(from: f32, to: f32) -> f32 { - libm::nextafterf(from, to) -} - -fn next_after_f64(from: f64, to: f64) -> f64 { - libm::nextafter(from, to) -} - -fn copy_sign_f32(x: f32, y: f32) -> f32 { - libm::copysignf(x, y) -} - -fn copy_sign_f64(x: f64, y: f64) -> f64 { - libm::copysign(x, y) -} - -pub fn library(manager: &mut ScriptManager) -> Option<()> { - manager.add_library_function(LIBRARY_NAME, "abs", abs_i32)?; - manager.add_library_function(LIBRARY_NAME, "labs", abs_i64)?; - manager.add_library_function(LIBRARY_NAME, "modf", mod_f32)?; - manager.add_library_function(LIBRARY_NAME, "mod", mod_f64)?; - manager.add_library_function(LIBRARY_NAME, "remf", remainder_f32)?; - manager.add_library_function(LIBRARY_NAME, "rem", remainder_f64)?; - manager.add_library_function(LIBRARY_NAME, "fmaf", mul_add_f32)?; - manager.add_library_function(LIBRARY_NAME, "fma", mul_add_f64)?; - manager.add_library_function(LIBRARY_NAME, "fdimf", fdim_f32)?; - manager.add_library_function(LIBRARY_NAME, "fdim", fdim_f64)?; - manager.add_library_function(LIBRARY_NAME, "expf", exp_f32)?; - manager.add_library_function(LIBRARY_NAME, "exp", exp_f64)?; - manager.add_library_function(LIBRARY_NAME, "exp2f", exp2_f32)?; - manager.add_library_function(LIBRARY_NAME, "exp2", exp2_f64)?; - manager.add_library_function(LIBRARY_NAME, "expm1f", expm1_f32)?; - manager.add_library_function(LIBRARY_NAME, "expm1", expm1_f64)?; - manager.add_library_function(LIBRARY_NAME, "lnf", ln_f32)?; - manager.add_library_function(LIBRARY_NAME, "ln", ln_f64)?; - manager.add_library_function(LIBRARY_NAME, "log2f", log2_f32)?; - manager.add_library_function(LIBRARY_NAME, "log2", log2_f64)?; - manager.add_library_function(LIBRARY_NAME, "log10f", log10_f32)?; - manager.add_library_function(LIBRARY_NAME, "log10", log10_f64)?; - manager.add_library_function(LIBRARY_NAME, "ln1pf", ln1p_f32)?; - manager.add_library_function(LIBRARY_NAME, "ln1p", ln1p_f64)?; - manager.add_library_function(LIBRARY_NAME, "powf", pow_f32)?; - manager.add_library_function(LIBRARY_NAME, "pow", pow_f64)?; - manager.add_library_function(LIBRARY_NAME, "cbrtf", cbrt_f32)?; - manager.add_library_function(LIBRARY_NAME, "cbrt", cbrt_f64)?; - manager.add_library_function(LIBRARY_NAME, "hypotf", hypotenuse_f32)?; - manager.add_library_function(LIBRARY_NAME, "hypot", hypotenuse_f64)?; - manager.add_library_function(LIBRARY_NAME, "sinf", sin_f32)?; - manager.add_library_function(LIBRARY_NAME, "sin", sin_f64)?; - manager.add_library_function(LIBRARY_NAME, "cosf", cos_f32)?; - manager.add_library_function(LIBRARY_NAME, "cos", cos_f64)?; - manager.add_library_function(LIBRARY_NAME, "tanf", tan_f32)?; - manager.add_library_function(LIBRARY_NAME, "tan", tan_f64)?; - manager.add_library_function(LIBRARY_NAME, "asinf", asin_f32)?; - manager.add_library_function(LIBRARY_NAME, "asin", asin_f64)?; - manager.add_library_function(LIBRARY_NAME, "acosf", acos_f32)?; - manager.add_library_function(LIBRARY_NAME, "acos", acos_f64)?; - manager.add_library_function(LIBRARY_NAME, "atanf", atan_f32)?; - manager.add_library_function(LIBRARY_NAME, "atan", atan_f64)?; - manager.add_library_function(LIBRARY_NAME, "sinhf", sinh_f32)?; - manager.add_library_function(LIBRARY_NAME, "sinh", sinh_f64)?; - manager.add_library_function(LIBRARY_NAME, "coshf", cosh_f32)?; - manager.add_library_function(LIBRARY_NAME, "cosh", cosh_f64)?; - manager.add_library_function(LIBRARY_NAME, "tanhf", tanh_f32)?; - manager.add_library_function(LIBRARY_NAME, "tanh", tanh_f64)?; - manager.add_library_function(LIBRARY_NAME, "asinhf", asinh_f32)?; - manager.add_library_function(LIBRARY_NAME, "asinh", asinh_f64)?; - manager.add_library_function(LIBRARY_NAME, "acoshf", acosh_f32)?; - manager.add_library_function(LIBRARY_NAME, "acosh", acosh_f64)?; - manager.add_library_function(LIBRARY_NAME, "atanhf", atanh_f32)?; - manager.add_library_function(LIBRARY_NAME, "atanh", atanh_f64)?; - manager.add_library_function(LIBRARY_NAME, "erff", erf_f32)?; - manager.add_library_function(LIBRARY_NAME, "erf", erf_f64)?; - manager.add_library_function(LIBRARY_NAME, "erfcf", erfc_f32)?; - manager.add_library_function(LIBRARY_NAME, "erfc", erfc_f64)?; - manager.add_library_function(LIBRARY_NAME, "gammaf", gamma_f32)?; - manager.add_library_function(LIBRARY_NAME, "gamma", gamma_f64)?; - manager.add_library_function(LIBRARY_NAME, "lgammaf", ln_gamma_f32)?; - manager.add_library_function(LIBRARY_NAME, "lgamma", ln_gamma_f64)?; - manager.add_library_function(LIBRARY_NAME, "lroundf", round_f32_i32)?; - manager.add_library_function(LIBRARY_NAME, "lround", round_f64_i32)?; - manager.add_library_function(LIBRARY_NAME, "llroundf", round_f32_i64)?; - manager.add_library_function(LIBRARY_NAME, "llround", round_f64_i64)?; - manager.add_library_function(LIBRARY_NAME, "frexpf", frexp_f32)?; - manager.add_library_function(LIBRARY_NAME, "frexp", frexp_f64)?; - manager.add_library_function(LIBRARY_NAME, "ldexpf", ldexp_f32)?; - manager.add_library_function(LIBRARY_NAME, "ldexp", ldexp_f64)?; - manager.add_library_function(LIBRARY_NAME, "modff", modf_f32)?; - manager.add_library_function(LIBRARY_NAME, "modf", modf_f64)?; - manager.add_library_function(LIBRARY_NAME, "ilogbf", logb_f32)?; - manager.add_library_function(LIBRARY_NAME, "ilogb", logb_f64)?; - manager.add_library_function(LIBRARY_NAME, "nextafterf", next_after_f32)?; - manager.add_library_function(LIBRARY_NAME, "nextafter", next_after_f64)?; - manager.add_library_function(LIBRARY_NAME, "copysignf", copy_sign_f32)?; - manager.add_library_function(LIBRARY_NAME, "copysign", copy_sign_f64)?; - - Some(()) -} +use crate::ScriptManager; + +use super::LIBRARY_NAME; + +fn abs_i32(n: i32) -> i32 { + n.abs() +} + +fn abs_i64(n: i64) -> i64 { + n.abs() +} + +fn mod_f32(x: f32, y: f32) -> f32 { + libm::fmodf(x, y) +} + +fn mod_f64(x: f64, y: f64) -> f64 { + libm::fmod(x, y) +} + +fn remainder_f32(x: f32, y: f32) -> f32 { + libm::remainderf(x, y) +} + +fn remainder_f64(x: f64, y: f64) -> f64 { + libm::remainder(x, y) +} + +fn mul_add_f32(x: f32, y: f32, z: f32) -> f32 { + x.mul_add(y, z) +} + +fn mul_add_f64(x: f64, y: f64, z: f64) -> f64 { + x.mul_add(y, z) +} + +fn fdim_f32(x: f32, y: f32) -> f32 { + libm::fdimf(x, y) +} + +fn fdim_f64(x: f64, y: f64) -> f64 { + libm::fdim(x, y) +} + +fn exp_f32(x: f32) -> f32 { + x.exp() +} + +fn exp_f64(x: f64) -> f64 { + x.exp() +} + +fn exp2_f32(x: f32) -> f32 { + x.exp2() +} + +fn exp2_f64(x: f64) -> f64 { + x.exp2() +} + +fn expm1_f32(x: f32) -> f32 { + x.exp_m1() +} + +fn expm1_f64(x: f64) -> f64 { + x.exp_m1() +} + +fn ln_f32(x: f32) -> f32 { + x.ln() +} + +fn ln_f64(x: f64) -> f64 { + x.ln() +} + +fn log10_f32(x: f32) -> f32 { + x.log10() +} + +fn log10_f64(x: f64) -> f64 { + x.log10() +} + +fn log2_f32(x: f32) -> f32 { + x.log2() +} + +fn log2_f64(x: f64) -> f64 { + x.log2() +} + +fn ln1p_f32(x: f32) -> f32 { + x.ln_1p() +} + +fn ln1p_f64(x: f64) -> f64 { + x.ln_1p() +} + +fn pow_f32(base: f32, exponent: f32) -> f32 { + base.powf(exponent) +} + +fn pow_f64(base: f64, exponent: f64) -> f64 { + base.powf(exponent) +} + +fn cbrt_f32(x: f32) -> f32 { + x.cbrt() +} + +fn cbrt_f64(x: f64) -> f64 { + x.cbrt() +} + +fn hypotenuse_f32(x: f32, y: f32) -> f32 { + x.hypot(y) +} + +fn hypotenuse_f64(x: f64, y: f64) -> f64 { + x.hypot(y) +} + +fn sin_f32(x: f32) -> f32 { + x.sin() +} + +fn sin_f64(x: f64) -> f64 { + x.sin() +} + +fn cos_f32(x: f32) -> f32 { + x.cos() +} + +fn cos_f64(x: f64) -> f64 { + x.cos() +} + +fn tan_f32(x: f32) -> f32 { + x.tan() +} + +fn tan_f64(x: f64) -> f64 { + x.tan() +} + +fn asin_f32(x: f32) -> f32 { + x.asin() +} + +fn asin_f64(x: f64) -> f64 { + x.asin() +} + +fn acos_f32(x: f32) -> f32 { + x.acos() +} + +fn acos_f64(x: f64) -> f64 { + x.acos() +} + +fn atan_f32(x: f32) -> f32 { + x.atan() +} + +fn atan_f64(x: f64) -> f64 { + x.atan() +} + +fn sinh_f32(x: f32) -> f32 { + x.sinh() +} + +fn sinh_f64(x: f64) -> f64 { + x.sinh() +} + +fn cosh_f32(x: f32) -> f32 { + x.cosh() +} + +fn cosh_f64(x: f64) -> f64 { + x.cosh() +} + +fn tanh_f32(x: f32) -> f32 { + x.tanh() +} + +fn tanh_f64(x: f64) -> f64 { + x.tanh() +} + +fn asinh_f32(x: f32) -> f32 { + x.asinh() +} + +fn asinh_f64(x: f64) -> f64 { + x.asinh() +} + +fn acosh_f32(x: f32) -> f32 { + x.acosh() +} + +fn acosh_f64(x: f64) -> f64 { + x.acosh() +} + +fn atanh_f32(x: f32) -> f32 { + x.atanh() +} + +fn atanh_f64(x: f64) -> f64 { + x.atanh() +} + +fn erf_f32(x: f32) -> f32 { + libm::erff(x) +} + +fn erf_f64(x: f64) -> f64 { + libm::erf(x) +} + +fn erfc_f32(x: f32) -> f32 { + libm::erfcf(x) +} + +fn erfc_f64(x: f64) -> f64 { + libm::erfc(x) +} + +fn gamma_f32(x: f32) -> f32 { + libm::tgammaf(x) +} + +fn gamma_f64(x: f64) -> f64 { + libm::tgamma(x) +} + +fn ln_gamma_f32(x: f32) -> f32 { + libm::lgammaf(x) +} + +fn ln_gamma_f64(x: f64) -> f64 { + libm::lgamma(x) +} + +fn round_f32_i32(x: f32) -> i32 { + x.round() as i32 +} + +fn round_f64_i32(x: f64) -> i32 { + x.round() as i32 +} + +fn round_f32_i64(x: f32) -> i64 { + x.round() as i64 +} + +fn round_f64_i64(x: f64) -> i64 { + x.round() as i64 +} + +fn frexp_f32(x: f32) -> (f32, i32) { + libm::frexpf(x) +} + +fn frexp_f64(x: f64) -> (f64, i32) { + libm::frexp(x) +} + +fn ldexp_f32(x: f32, exp: i32) -> f32 { + libm::ldexpf(x, exp) +} + +fn ldexp_f64(x: f64, exp: i32) -> f64 { + libm::ldexp(x, exp) +} + +fn modf_f32(x: f32) -> (f32, f32) { + libm::modff(x) +} + +fn modf_f64(x: f64) -> (f64, f64) { + libm::modf(x) +} + +fn logb_f32(x: f32) -> i32 { + libm::ilogbf(x) +} + +fn logb_f64(x: f64) -> i32 { + libm::ilogb(x) +} + +fn next_after_f32(from: f32, to: f32) -> f32 { + libm::nextafterf(from, to) +} + +fn next_after_f64(from: f64, to: f64) -> f64 { + libm::nextafter(from, to) +} + +fn copy_sign_f32(x: f32, y: f32) -> f32 { + libm::copysignf(x, y) +} + +fn copy_sign_f64(x: f64, y: f64) -> f64 { + libm::copysign(x, y) +} + +pub fn library(manager: &mut ScriptManager) -> Option<()> { + manager.add_library_function(LIBRARY_NAME, "abs", abs_i32)?; + manager.add_library_function(LIBRARY_NAME, "labs", abs_i64)?; + manager.add_library_function(LIBRARY_NAME, "modf", mod_f32)?; + manager.add_library_function(LIBRARY_NAME, "mod", mod_f64)?; + manager.add_library_function(LIBRARY_NAME, "remf", remainder_f32)?; + manager.add_library_function(LIBRARY_NAME, "rem", remainder_f64)?; + manager.add_library_function(LIBRARY_NAME, "fmaf", mul_add_f32)?; + manager.add_library_function(LIBRARY_NAME, "fma", mul_add_f64)?; + manager.add_library_function(LIBRARY_NAME, "fdimf", fdim_f32)?; + manager.add_library_function(LIBRARY_NAME, "fdim", fdim_f64)?; + manager.add_library_function(LIBRARY_NAME, "expf", exp_f32)?; + manager.add_library_function(LIBRARY_NAME, "exp", exp_f64)?; + manager.add_library_function(LIBRARY_NAME, "exp2f", exp2_f32)?; + manager.add_library_function(LIBRARY_NAME, "exp2", exp2_f64)?; + manager.add_library_function(LIBRARY_NAME, "expm1f", expm1_f32)?; + manager.add_library_function(LIBRARY_NAME, "expm1", expm1_f64)?; + manager.add_library_function(LIBRARY_NAME, "lnf", ln_f32)?; + manager.add_library_function(LIBRARY_NAME, "ln", ln_f64)?; + manager.add_library_function(LIBRARY_NAME, "log2f", log2_f32)?; + manager.add_library_function(LIBRARY_NAME, "log2", log2_f64)?; + manager.add_library_function(LIBRARY_NAME, "log10f", log10_f32)?; + manager.add_library_function(LIBRARY_NAME, "log10", log10_f64)?; + manager.add_library_function(LIBRARY_NAME, "ln1pf", ln1p_f32)?; + manager.add_library_function(LIBRARY_NAME, "ln1p", ln1p_f64)?; + manager.add_library_function(LIBRARY_NAME, "powf", pow_f32)?; + manager.add_library_function(LIBRARY_NAME, "pow", pow_f64)?; + manager.add_library_function(LIBRARY_NAME, "cbrtf", cbrt_f32)?; + manager.add_library_function(LIBRARY_NAME, "cbrt", cbrt_f64)?; + manager.add_library_function(LIBRARY_NAME, "hypotf", hypotenuse_f32)?; + manager.add_library_function(LIBRARY_NAME, "hypot", hypotenuse_f64)?; + manager.add_library_function(LIBRARY_NAME, "sinf", sin_f32)?; + manager.add_library_function(LIBRARY_NAME, "sin", sin_f64)?; + manager.add_library_function(LIBRARY_NAME, "cosf", cos_f32)?; + manager.add_library_function(LIBRARY_NAME, "cos", cos_f64)?; + manager.add_library_function(LIBRARY_NAME, "tanf", tan_f32)?; + manager.add_library_function(LIBRARY_NAME, "tan", tan_f64)?; + manager.add_library_function(LIBRARY_NAME, "asinf", asin_f32)?; + manager.add_library_function(LIBRARY_NAME, "asin", asin_f64)?; + manager.add_library_function(LIBRARY_NAME, "acosf", acos_f32)?; + manager.add_library_function(LIBRARY_NAME, "acos", acos_f64)?; + manager.add_library_function(LIBRARY_NAME, "atanf", atan_f32)?; + manager.add_library_function(LIBRARY_NAME, "atan", atan_f64)?; + manager.add_library_function(LIBRARY_NAME, "sinhf", sinh_f32)?; + manager.add_library_function(LIBRARY_NAME, "sinh", sinh_f64)?; + manager.add_library_function(LIBRARY_NAME, "coshf", cosh_f32)?; + manager.add_library_function(LIBRARY_NAME, "cosh", cosh_f64)?; + manager.add_library_function(LIBRARY_NAME, "tanhf", tanh_f32)?; + manager.add_library_function(LIBRARY_NAME, "tanh", tanh_f64)?; + manager.add_library_function(LIBRARY_NAME, "asinhf", asinh_f32)?; + manager.add_library_function(LIBRARY_NAME, "asinh", asinh_f64)?; + manager.add_library_function(LIBRARY_NAME, "acoshf", acosh_f32)?; + manager.add_library_function(LIBRARY_NAME, "acosh", acosh_f64)?; + manager.add_library_function(LIBRARY_NAME, "atanhf", atanh_f32)?; + manager.add_library_function(LIBRARY_NAME, "atanh", atanh_f64)?; + manager.add_library_function(LIBRARY_NAME, "erff", erf_f32)?; + manager.add_library_function(LIBRARY_NAME, "erf", erf_f64)?; + manager.add_library_function(LIBRARY_NAME, "erfcf", erfc_f32)?; + manager.add_library_function(LIBRARY_NAME, "erfc", erfc_f64)?; + manager.add_library_function(LIBRARY_NAME, "gammaf", gamma_f32)?; + manager.add_library_function(LIBRARY_NAME, "gamma", gamma_f64)?; + manager.add_library_function(LIBRARY_NAME, "lgammaf", ln_gamma_f32)?; + manager.add_library_function(LIBRARY_NAME, "lgamma", ln_gamma_f64)?; + manager.add_library_function(LIBRARY_NAME, "lroundf", round_f32_i32)?; + manager.add_library_function(LIBRARY_NAME, "lround", round_f64_i32)?; + manager.add_library_function(LIBRARY_NAME, "llroundf", round_f32_i64)?; + manager.add_library_function(LIBRARY_NAME, "llround", round_f64_i64)?; + manager.add_library_function(LIBRARY_NAME, "frexpf", frexp_f32)?; + manager.add_library_function(LIBRARY_NAME, "frexp", frexp_f64)?; + manager.add_library_function(LIBRARY_NAME, "ldexpf", ldexp_f32)?; + manager.add_library_function(LIBRARY_NAME, "ldexp", ldexp_f64)?; + manager.add_library_function(LIBRARY_NAME, "modff", modf_f32)?; + manager.add_library_function(LIBRARY_NAME, "modf", modf_f64)?; + manager.add_library_function(LIBRARY_NAME, "ilogbf", logb_f32)?; + manager.add_library_function(LIBRARY_NAME, "ilogb", logb_f64)?; + manager.add_library_function(LIBRARY_NAME, "nextafterf", next_after_f32)?; + manager.add_library_function(LIBRARY_NAME, "nextafter", next_after_f64)?; + manager.add_library_function(LIBRARY_NAME, "copysignf", copy_sign_f32)?; + manager.add_library_function(LIBRARY_NAME, "copysign", copy_sign_f64)?; + + Some(()) +} diff --git a/scripts/src/libs/mod.rs b/scripts/src/libs/mod.rs index c6b1ffc..b77a0e2 100644 --- a/scripts/src/libs/mod.rs +++ b/scripts/src/libs/mod.rs @@ -1,19 +1,19 @@ -use crate::ScriptManager; - -mod allocate; -mod buffer; -mod ctype; -mod math; -mod system; - -const LIBRARY_NAME: &str = "alligator"; - -pub fn add_alligator_library(manager: &mut ScriptManager) -> Option<()> { - allocate::library(manager)?; - buffer::library(manager)?; - ctype::library(manager)?; - math::library(manager)?; - system::library(manager)?; - - Some(()) -} +use crate::ScriptManager; + +mod allocate; +mod buffer; +mod ctype; +mod math; +mod system; + +const LIBRARY_NAME: &str = "alligator"; + +pub fn add_alligator_library(manager: &mut ScriptManager) -> Option<()> { + allocate::library(manager)?; + buffer::library(manager)?; + ctype::library(manager)?; + math::library(manager)?; + system::library(manager)?; + + Some(()) +} diff --git a/scripts/src/libs/system.rs b/scripts/src/libs/system.rs index 9c5a50c..4c7455b 100644 --- a/scripts/src/libs/system.rs +++ b/scripts/src/libs/system.rs @@ -1,154 +1,154 @@ -use std::borrow::Cow; -use std::mem::align_of; - -use chrono::Offset; -use wasmtime::{Caller, Memory}; - -use crate::{ScriptManager, WasmScriptState}; - -use super::LIBRARY_NAME; - -pub fn _get_memory<'a>(caller: &'a mut Caller) -> (Memory, &'a mut [u8]) { - let memory = caller.get_export("memory").unwrap().into_memory().unwrap(); - let mem_ptr = memory.data_mut(caller); - (memory, mem_ptr) -} - -fn _get_string<'a>( - caller: &'a mut Caller, - offset: u32, - length: u32, -) -> Option> { - let (_, mem_ptr) = _get_memory(caller); - if (offset as usize + length as usize) > mem_ptr.len() { - return None; - } - - Some(String::from_utf8_lossy( - &mem_ptr[offset as usize..length as usize], - )) -} - -fn _log(caller: &mut Caller, level: log::Level, message: u32, length: u32) -> u32 { - let Some(message) = _get_string(caller, message, length) else { - return 4; - }; - log::log!(level, "{}", message); - 0 -} - -pub fn _alloc<'a>( - mut caller: &'a mut Caller, - size: u32, - align: u32, -) -> Option<(u32, &'a mut [u8])> { - // find bumper location in memory - let bump_offset = caller.data().bump_pointer; - let (memory, memory_ptr) = _get_memory(caller); - let bump_ptr = &memory_ptr[bump_offset as usize..]; - - // calculate pointer to the new allocation - let offset = bump_ptr.as_ptr().align_offset(align as usize); - let new_offset = bump_offset + offset as u32; - - // update bump pointer - let bump_offset = &mut caller.data_mut().bump_pointer; - *bump_offset = new_offset + size; - - // grow memory if necessary - let bump_offset = *bump_offset; - if memory.data_size(&caller) < bump_offset as usize { - let delta = (size + offset as u32) / (64 * 1024) + 1; - if memory.grow(&mut caller, delta as u64).is_err() { - return None; - } - } - - let new_ptr = &mut _get_memory(caller).1[new_offset as usize..size as usize]; - Some((new_offset, new_ptr)) -} - -fn allocate(mut caller: Caller, size: u32, align: u32) -> u32 { - match _alloc(&mut caller, size, align) { - Some((ptr, _)) => ptr, - None => 0, - } -} - -fn free_sized(mut caller: Caller<'_, WasmScriptState>, ptr: u32, size: u32) -> u32 { - let bump_offset = &mut caller.data_mut().bump_pointer; - if ptr + size == *bump_offset { - *bump_offset = ptr; - } - - 0 -} - -fn free_aligned_sized( - caller: Caller<'_, WasmScriptState>, - ptr: u32, - _alignment: u32, - size: u32, -) -> u32 { - free_sized(caller, ptr, size) -} - -fn env_var(mut caller: Caller<'_, WasmScriptState>, name: u32, length: u32) -> u32 { - let Some(name) = _get_string(&mut caller, name, length) else { - return 4; - }; - let Ok(value) = std::env::var(name.to_string()) else { - return 1; - }; - - let Some((offset, ptr)) = _alloc(&mut caller, value.len() as u32, align_of::() as u32) - else { - return 0; - }; - ptr.clone_from_slice(value.as_bytes()); - - offset -} - -fn random_number() -> u64 { - rand::random() -} - -fn current_time_utc() -> (i64, u32) { - let duration = chrono::Utc::now() - chrono::DateTime::::MIN_UTC; - ( - duration.num_seconds(), - duration.to_std().unwrap().subsec_nanos(), - ) -} - -fn local_offset() -> i32 { - chrono::Local::now().offset().fix().local_minus_utc() -} - -fn log(mut caller: Caller<'_, WasmScriptState>, message: u32, length: u32) { - _log(&mut caller, log::Level::Info, message, length); -} - -fn log_warn(mut caller: Caller<'_, WasmScriptState>, message: u32, length: u32) { - _log(&mut caller, log::Level::Warn, message, length); -} - -fn log_error(mut caller: Caller<'_, WasmScriptState>, message: u32, length: u32) { - _log(&mut caller, log::Level::Error, message, length); -} - -pub fn library(manager: &mut ScriptManager) -> Option<()> { - manager.add_library_function(LIBRARY_NAME, "aligned_alloc", allocate)?; - manager.add_library_function(LIBRARY_NAME, "free_sized", free_sized)?; - manager.add_library_function(LIBRARY_NAME, "free_aligned_sized", free_aligned_sized)?; - manager.add_library_function(LIBRARY_NAME, "env_var", env_var)?; - manager.add_library_function(LIBRARY_NAME, "random_number", random_number)?; - manager.add_library_function(LIBRARY_NAME, "current_time_utc", current_time_utc)?; - manager.add_library_function(LIBRARY_NAME, "local_offset", local_offset)?; - manager.add_library_function(LIBRARY_NAME, "log", log)?; - manager.add_library_function(LIBRARY_NAME, "log_warn", log_warn)?; - manager.add_library_function(LIBRARY_NAME, "log_error", log_error)?; - - Some(()) -} +use std::borrow::Cow; +use std::mem::align_of; + +use chrono::Offset; +use wasmtime::{Caller, Memory}; + +use crate::{ScriptManager, WasmScriptState}; + +use super::LIBRARY_NAME; + +pub fn _get_memory<'a>(caller: &'a mut Caller) -> (Memory, &'a mut [u8]) { + let memory = caller.get_export("memory").unwrap().into_memory().unwrap(); + let mem_ptr = memory.data_mut(caller); + (memory, mem_ptr) +} + +fn _get_string<'a>( + caller: &'a mut Caller, + offset: u32, + length: u32, +) -> Option> { + let (_, mem_ptr) = _get_memory(caller); + if (offset as usize + length as usize) > mem_ptr.len() { + return None; + } + + Some(String::from_utf8_lossy( + &mem_ptr[offset as usize..length as usize], + )) +} + +fn _log(caller: &mut Caller, level: log::Level, message: u32, length: u32) -> u32 { + let Some(message) = _get_string(caller, message, length) else { + return 4; + }; + log::log!(level, "{}", message); + 0 +} + +pub fn _alloc<'a>( + mut caller: &'a mut Caller, + size: u32, + align: u32, +) -> Option<(u32, &'a mut [u8])> { + // find bumper location in memory + let bump_offset = caller.data().bump_pointer; + let (memory, memory_ptr) = _get_memory(caller); + let bump_ptr = &memory_ptr[bump_offset as usize..]; + + // calculate pointer to the new allocation + let offset = bump_ptr.as_ptr().align_offset(align as usize); + let new_offset = bump_offset + offset as u32; + + // update bump pointer + let bump_offset = &mut caller.data_mut().bump_pointer; + *bump_offset = new_offset + size; + + // grow memory if necessary + let bump_offset = *bump_offset; + if memory.data_size(&caller) < bump_offset as usize { + let delta = (size + offset as u32) / (64 * 1024) + 1; + if memory.grow(&mut caller, delta as u64).is_err() { + return None; + } + } + + let new_ptr = &mut _get_memory(caller).1[new_offset as usize..size as usize]; + Some((new_offset, new_ptr)) +} + +fn allocate(mut caller: Caller, size: u32, align: u32) -> u32 { + match _alloc(&mut caller, size, align) { + Some((ptr, _)) => ptr, + None => 0, + } +} + +fn free_sized(mut caller: Caller<'_, WasmScriptState>, ptr: u32, size: u32) -> u32 { + let bump_offset = &mut caller.data_mut().bump_pointer; + if ptr + size == *bump_offset { + *bump_offset = ptr; + } + + 0 +} + +fn free_aligned_sized( + caller: Caller<'_, WasmScriptState>, + ptr: u32, + _alignment: u32, + size: u32, +) -> u32 { + free_sized(caller, ptr, size) +} + +fn env_var(mut caller: Caller<'_, WasmScriptState>, name: u32, length: u32) -> u32 { + let Some(name) = _get_string(&mut caller, name, length) else { + return 4; + }; + let Ok(value) = std::env::var(name.to_string()) else { + return 1; + }; + + let Some((offset, ptr)) = _alloc(&mut caller, value.len() as u32, align_of::() as u32) + else { + return 0; + }; + ptr.clone_from_slice(value.as_bytes()); + + offset +} + +fn random_number() -> u64 { + rand::random() +} + +fn current_time_utc() -> (i64, u32) { + let duration = chrono::Utc::now() - chrono::DateTime::::MIN_UTC; + ( + duration.num_seconds(), + duration.to_std().unwrap().subsec_nanos(), + ) +} + +fn local_offset() -> i32 { + chrono::Local::now().offset().fix().local_minus_utc() +} + +fn log(mut caller: Caller<'_, WasmScriptState>, message: u32, length: u32) { + _log(&mut caller, log::Level::Info, message, length); +} + +fn log_warn(mut caller: Caller<'_, WasmScriptState>, message: u32, length: u32) { + _log(&mut caller, log::Level::Warn, message, length); +} + +fn log_error(mut caller: Caller<'_, WasmScriptState>, message: u32, length: u32) { + _log(&mut caller, log::Level::Error, message, length); +} + +pub fn library(manager: &mut ScriptManager) -> Option<()> { + manager.add_library_function(LIBRARY_NAME, "aligned_alloc", allocate)?; + manager.add_library_function(LIBRARY_NAME, "free_sized", free_sized)?; + manager.add_library_function(LIBRARY_NAME, "free_aligned_sized", free_aligned_sized)?; + manager.add_library_function(LIBRARY_NAME, "env_var", env_var)?; + manager.add_library_function(LIBRARY_NAME, "random_number", random_number)?; + manager.add_library_function(LIBRARY_NAME, "current_time_utc", current_time_utc)?; + manager.add_library_function(LIBRARY_NAME, "local_offset", local_offset)?; + manager.add_library_function(LIBRARY_NAME, "log", log)?; + manager.add_library_function(LIBRARY_NAME, "log_warn", log_warn)?; + manager.add_library_function(LIBRARY_NAME, "log_error", log_error)?; + + Some(()) +} diff --git a/scripts/src/vtable.rs b/scripts/src/vtable.rs index 0fbb324..33b71ab 100644 --- a/scripts/src/vtable.rs +++ b/scripts/src/vtable.rs @@ -1,10 +1,10 @@ -/// A trait for scripts -pub trait ScriptTable: Send + Sync { - /// This is called whenever the script is enabled - fn begin(&mut self); - - /// This is called every frame - fn update(&mut self); -} - -pub type VTableScript = &'static mut dyn ScriptTable; +/// A trait for scripts +pub trait ScriptTable: Send + Sync { + /// This is called whenever the script is enabled + fn begin(&mut self); + + /// This is called every frame + fn update(&mut self); +} + +pub type VTableScript = &'static mut dyn ScriptTable; diff --git a/scripts/src/wasm.rs b/scripts/src/wasm.rs index 7ac9dae..06d840f 100644 --- a/scripts/src/wasm.rs +++ b/scripts/src/wasm.rs @@ -1,170 +1,170 @@ -use std::path::Path; - -use thiserror::Error; -use wasmtime::{Engine, Instance, Linker, Module, Mutability, Store, ValType}; - -// It's a bad idea to have the memory allocator return a number that could also -// indicate an error, so this is set to be at least eight. -const MIN_BUMP_POINTER: u32 = 8; - -/// Information about the script which can be used by functions it calls -pub struct WasmScriptState { - pub bump_pointer: u32, - pub trusted: bool, -} - -impl WasmScriptState { - pub const fn new(trusted: bool) -> Self { - Self { - bump_pointer: MIN_BUMP_POINTER, - trusted, - } - } -} - -/// A script, its path in the filesystem, and some metadata -pub struct WasmScript { - path: Box, - module: Module, - store: Store, - instance: Instance, - trusted: bool, - //state: Value, -} - -#[derive(Debug, Error)] -pub enum InvalidWasmScript { - #[error("There is no exported memory called 'memory', which is required")] - NoExportedMemory, - #[error("The exported symbol, 'memory' must be a memory")] - MemoryIsNotAMemory, - #[error("The memory must be 32-bit, not 64-bit")] - MemoryTooLarge, - #[error("There is no exported global called '__heap_base', which is required")] - NoHeapBase, - #[error("The exported symbol, '__heap_base' must be a constant global")] - HeapBaseIsNotGlobal, - #[error("The exported global, '__heap_base' must be an i32")] - HeapBaseMustBeI32, - #[error("The exported global, '__heap_base' must be a constant")] - HeapBaseMustBeConstant, - #[error("{}", .0)] - CompilerError(#[from] wasmtime::Error), -} - -/// Confirms that the module can be used as a script -fn validate_module(module: &Module) -> Result<(), InvalidWasmScript> { - // verify that memory is exported from this module and is valid - let Some(export) = module.get_export("memory") else { - return Err(InvalidWasmScript::NoExportedMemory); - }; - let Some(memory) = export.memory() else { - return Err(InvalidWasmScript::MemoryIsNotAMemory); - }; - if memory.is_64() { - return Err(InvalidWasmScript::MemoryTooLarge); - } - - // verify __heap_base global - let Some(export) = module.get_export("__heap_base") else { - return Err(InvalidWasmScript::NoHeapBase); - }; - let Some(heap_base) = export.global() else { - return Err(InvalidWasmScript::HeapBaseIsNotGlobal); - }; - if *heap_base.content() != ValType::I32 { - return Err(InvalidWasmScript::HeapBaseMustBeI32); - } - if heap_base.mutability() != Mutability::Const { - return Err(InvalidWasmScript::HeapBaseMustBeConstant); - } - - Ok(()) -} - -impl WasmScript { - pub fn new( - path: &Path, - engine: &Engine, - linker: &Linker, - trusted: bool, - ) -> Result { - let module = Module::from_file(engine, path)?; - validate_module(&module)?; - let mut store = Store::new(engine, WasmScriptState::new(trusted)); - let instance = linker.instantiate(&mut store, &module)?; - - Ok(Self { - path: path.into(), - module, - store, - instance, - trusted, - }) - } - - /// Reload from the filesystem - pub fn reload( - &mut self, - engine: &Engine, - linker: &Linker, - ) -> Result<(), InvalidWasmScript> { - let module = Module::from_file(engine, &self.path)?; - validate_module(&module)?; - self.store = Store::new(engine, WasmScriptState::new(self.trusted)); - self.instance = linker.instantiate(&mut self.store, &module)?; - - Ok(()) - } - - /// Re-links the module. This doesn't load the module from the filesystem. - pub fn relink( - &mut self, - engine: &Engine, - linker: &Linker, - ) -> Result<(), InvalidWasmScript> { - self.store = Store::new(engine, WasmScriptState::new(self.trusted)); - self.instance = linker.instantiate(&mut self.store, &self.module)?; - Ok(()) - } - - pub fn is_trusted(&self) -> bool { - self.trusted - } - - pub fn trust(&mut self) { - self.trusted = true; - } - - pub fn untrust(&mut self) { - self.trusted = false; - } - - fn run_function_if_exists(&mut self, name: &str) -> wasmtime::Result<()> { - // set bump pointer to the start of the heap - let heap_base = self - .instance - .get_global(&mut self.store, "__heap_base") - .unwrap() - .get(&mut self.store) - .unwrap_i32(); - let bump_ptr = &mut self.store.data_mut().bump_pointer; - *bump_ptr = (heap_base as u32).max(MIN_BUMP_POINTER); - - // call the given function - let func = self.instance.get_func(&mut self.store, name); - if let Some(func) = func { - func.call(&mut self.store, &[], &mut [])?; - } - - Ok(()) - } - - pub fn begin(&mut self) -> wasmtime::Result<()> { - self.run_function_if_exists("begin") - } - - pub fn update(&mut self) -> wasmtime::Result<()> { - self.run_function_if_exists("update") - } -} +use std::path::Path; + +use thiserror::Error; +use wasmtime::{Engine, Instance, Linker, Module, Mutability, Store, ValType}; + +// It's a bad idea to have the memory allocator return a number that could also +// indicate an error, so this is set to be at least eight. +const MIN_BUMP_POINTER: u32 = 8; + +/// Information about the script which can be used by functions it calls +pub struct WasmScriptState { + pub bump_pointer: u32, + pub trusted: bool, +} + +impl WasmScriptState { + pub const fn new(trusted: bool) -> Self { + Self { + bump_pointer: MIN_BUMP_POINTER, + trusted, + } + } +} + +/// A script, its path in the filesystem, and some metadata +pub struct WasmScript { + path: Box, + module: Module, + store: Store, + instance: Instance, + trusted: bool, + //state: Value, +} + +#[derive(Debug, Error)] +pub enum InvalidWasmScript { + #[error("There is no exported memory called 'memory', which is required")] + NoExportedMemory, + #[error("The exported symbol, 'memory' must be a memory")] + MemoryIsNotAMemory, + #[error("The memory must be 32-bit, not 64-bit")] + MemoryTooLarge, + #[error("There is no exported global called '__heap_base', which is required")] + NoHeapBase, + #[error("The exported symbol, '__heap_base' must be a constant global")] + HeapBaseIsNotGlobal, + #[error("The exported global, '__heap_base' must be an i32")] + HeapBaseMustBeI32, + #[error("The exported global, '__heap_base' must be a constant")] + HeapBaseMustBeConstant, + #[error("{}", .0)] + CompilerError(#[from] wasmtime::Error), +} + +/// Confirms that the module can be used as a script +fn validate_module(module: &Module) -> Result<(), InvalidWasmScript> { + // verify that memory is exported from this module and is valid + let Some(export) = module.get_export("memory") else { + return Err(InvalidWasmScript::NoExportedMemory); + }; + let Some(memory) = export.memory() else { + return Err(InvalidWasmScript::MemoryIsNotAMemory); + }; + if memory.is_64() { + return Err(InvalidWasmScript::MemoryTooLarge); + } + + // verify __heap_base global + let Some(export) = module.get_export("__heap_base") else { + return Err(InvalidWasmScript::NoHeapBase); + }; + let Some(heap_base) = export.global() else { + return Err(InvalidWasmScript::HeapBaseIsNotGlobal); + }; + if *heap_base.content() != ValType::I32 { + return Err(InvalidWasmScript::HeapBaseMustBeI32); + } + if heap_base.mutability() != Mutability::Const { + return Err(InvalidWasmScript::HeapBaseMustBeConstant); + } + + Ok(()) +} + +impl WasmScript { + pub fn new( + path: &Path, + engine: &Engine, + linker: &Linker, + trusted: bool, + ) -> Result { + let module = Module::from_file(engine, path)?; + validate_module(&module)?; + let mut store = Store::new(engine, WasmScriptState::new(trusted)); + let instance = linker.instantiate(&mut store, &module)?; + + Ok(Self { + path: path.into(), + module, + store, + instance, + trusted, + }) + } + + /// Reload from the filesystem + pub fn reload( + &mut self, + engine: &Engine, + linker: &Linker, + ) -> Result<(), InvalidWasmScript> { + let module = Module::from_file(engine, &self.path)?; + validate_module(&module)?; + self.store = Store::new(engine, WasmScriptState::new(self.trusted)); + self.instance = linker.instantiate(&mut self.store, &module)?; + + Ok(()) + } + + /// Re-links the module. This doesn't load the module from the filesystem. + pub fn relink( + &mut self, + engine: &Engine, + linker: &Linker, + ) -> Result<(), InvalidWasmScript> { + self.store = Store::new(engine, WasmScriptState::new(self.trusted)); + self.instance = linker.instantiate(&mut self.store, &self.module)?; + Ok(()) + } + + pub fn is_trusted(&self) -> bool { + self.trusted + } + + pub fn trust(&mut self) { + self.trusted = true; + } + + pub fn untrust(&mut self) { + self.trusted = false; + } + + fn run_function_if_exists(&mut self, name: &str) -> wasmtime::Result<()> { + // set bump pointer to the start of the heap + let heap_base = self + .instance + .get_global(&mut self.store, "__heap_base") + .unwrap() + .get(&mut self.store) + .unwrap_i32(); + let bump_ptr = &mut self.store.data_mut().bump_pointer; + *bump_ptr = (heap_base as u32).max(MIN_BUMP_POINTER); + + // call the given function + let func = self.instance.get_func(&mut self.store, name); + if let Some(func) = func { + func.call(&mut self.store, &[], &mut [])?; + } + + Ok(()) + } + + pub fn begin(&mut self) -> wasmtime::Result<()> { + self.run_function_if_exists("begin") + } + + pub fn update(&mut self) -> wasmtime::Result<()> { + self.run_function_if_exists("update") + } +} diff --git a/shell-spec.txt b/shell-spec.txt index dda23c7..d0238fd 100644 --- a/shell-spec.txt +++ b/shell-spec.txt @@ -1,13 +1,16 @@ -# Alligator Shell Specification - -Default Port Number: 26009 -Using TCP Protocol - -## Runtime to Editor - -runtimelog [trace|debug|info|warn|error] FILE:LINE MSG -scriptlog [trace|debug|info|warn|error] FILE:LINE MSG - -## Editor to Runtime - -stop +# Alligator Shell Specification + +Default Port Number: 26009 +Using TCP Protocol + +## Runtime to Editor + +runtimelog [trace|debug|info|warn|error] FILE:LINE MSG +scriptlog [trace|debug|info|warn|error] FILE:LINE MSG +frametime UNIX_MICROSECONDS +scopestart SCOPENAME UNIX_MICROSECONDS +scopeend UNIX_MICROSECONDS + +## Editor to Runtime + +stop diff --git a/src/main.rs b/src/main.rs index ade657e..c8d4618 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,145 +1,154 @@ -use std::collections::HashMap; -use std::fs::File; -use std::io::Read; -use std::num::NonZeroU32; -use std::path::Path; - -use alligator_scripts::ScriptManager; -use alligator_sprites::SpriteManager; -use alligator_sys::{Renderer, RendererConfig, Window, WindowConfig, WindowEvent}; - -use serde::Deserialize; -use sha3::{Digest, Sha3_256}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] -enum ScriptType { - Wasm, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] -enum ConfigWindowMode { - Windowed, - BorderlessFullscreen, -} - -#[derive(Debug, Clone, Deserialize)] -struct ConfigScript { - path: Box, - script_type: ScriptType, - hash: Option, -} - -#[derive(Debug, Clone, Deserialize)] -struct ConfigSprite { - texture: String, - x: f32, - y: f32, - z: f32, -} - -#[derive(Debug, Clone, Deserialize)] -struct ConfigTexture { - size: usize, - path: Box, -} - -#[derive(Debug, Clone, Deserialize)] -struct Scene { - initial_sprites: HashMap, - initial_scripts: Vec, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct Config { - alligator_version: usize, - scenes: HashMap, - textures: HashMap, - scripts: HashMap, - default_scene: String, - sprite_manager_capacity: u32, - default_window_width: NonZeroU32, - default_window_height: NonZeroU32, - default_window_mode: ConfigWindowMode, - window_title: String, - vsync: bool, -} - -fn sprite_manager(config: &Config) -> SpriteManager { - SpriteManager::with_capacity(config.sprite_manager_capacity as usize) -} - -fn script_manager(config: &Config) -> ScriptManager { - let mut scripts = ScriptManager::new(); - for (key, script) in config.scripts.iter() { - let path = script.path.clone(); - let trusted = if let Some(hash) = &script.hash { - let mut bytes = Vec::new(); - let mut msg = File::open(&path).unwrap(); - msg.read_to_end(&mut bytes).unwrap(); - let mut hasher = Sha3_256::new(); - hasher.update(bytes); - let result = hasher.finalize(); - hash.as_bytes() == &result[..] - } else { - false - }; - - scripts - .add_wasm_script(key.clone().into_boxed_str(), path, trusted) - .unwrap(); - } - - scripts -} - -fn window(config: &Config) -> Window { - let config = WindowConfig { - title: config.window_title.clone(), - default_width: config.default_window_width.get(), - default_height: config.default_window_height.get(), - default_x: 100, - default_y: 100, - borderless_fullscreen: config.default_window_mode == ConfigWindowMode::BorderlessFullscreen, - visible: false, - }; - - Window::new(config) -} - -fn renderer(config: &Config, window: &Window) -> Renderer { - let config = RendererConfig { - width: config.default_window_width.get(), - height: config.default_window_height.get(), - instance_capacity: config.sprite_manager_capacity, - fullscreen: false, - vsync: config.vsync, - }; - - Renderer::new(window, config) -} - -fn main() { - std::env::set_current_dir(std::env::current_exe().unwrap().parent().unwrap()).unwrap(); - let config = File::open("game.json").unwrap(); - let config: Config = serde_json::from_reader(config).unwrap(); - - let sprites = sprite_manager(&config); - let scripts = script_manager(&config); - let mut window = window(&config); - - window.wait_for_resume(); - - let mut renderer = renderer(&config, &window); - window.set_visible(true); - - window.run(move |window, event| match event { - Some(WindowEvent::RedrawRequest) => { - renderer.render_frame(); - } - Some(WindowEvent::CloseRequest) => { - std::process::exit(0); - } - Some(_) => (), - None => window.request_redraw(), - }) -} +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; +use std::num::NonZeroU32; +use std::path::Path; + +use alligator_console::Console; +use alligator_profiler as profile; +use alligator_scripts::ScriptManager; +use alligator_sprites::SpriteManager; +use alligator_sys::{Renderer, RendererConfig, Window, WindowConfig, WindowEvent}; + +use pollster::FutureExt; +use serde::Deserialize; +use sha3::{Digest, Sha3_256}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +enum ScriptType { + Wasm, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +enum ConfigWindowMode { + Windowed, + BorderlessFullscreen, +} + +#[derive(Debug, Clone, Deserialize)] +struct ConfigScript { + path: Box, + script_type: ScriptType, + hash: Option, +} + +#[derive(Debug, Clone, Deserialize)] +struct ConfigSprite { + texture: String, + x: f32, + y: f32, + z: f32, +} + +#[derive(Debug, Clone, Deserialize)] +struct ConfigTexture { + size: usize, + path: Box, +} + +#[derive(Debug, Clone, Deserialize)] +struct Scene { + initial_sprites: HashMap, + initial_scripts: Vec, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Config { + alligator_version: String, + scenes: HashMap, + textures: HashMap, + scripts: HashMap, + default_scene: String, + sprite_manager_capacity: u32, + default_window_width: Option, + default_window_height: Option, + default_window_mode: ConfigWindowMode, + window_title: String, + vsync: bool, +} + +fn sprite_manager(config: &Config) -> SpriteManager { + SpriteManager::with_capacity(config.sprite_manager_capacity as usize) +} + +fn script_manager(config: &Config) -> ScriptManager { + let mut scripts = ScriptManager::new(); + for (key, script) in config.scripts.iter() { + let path = script.path.clone(); + let trusted = if let Some(hash) = &script.hash { + let mut bytes = Vec::new(); + let mut msg = File::open(&path).unwrap(); + msg.read_to_end(&mut bytes).unwrap(); + let mut hasher = Sha3_256::new(); + hasher.update(bytes); + let result = hasher.finalize(); + hash.as_bytes() == &result[..] + } else { + false + }; + + scripts + .add_wasm_script(key.clone().into_boxed_str(), path, trusted) + .unwrap(); + } + + scripts +} + +fn window(config: &Config) -> Window { + let config = WindowConfig { + title: config.window_title.clone(), + default_width: config.default_window_width.get(), + default_height: config.default_window_height.get(), + default_x: 100, + default_y: 100, + borderless_fullscreen: config.default_window_mode == ConfigWindowMode::BorderlessFullscreen, + visible: false, + }; + + Window::new(config) +} + +fn renderer(config: &Config, window: &Window) -> Renderer { + let config = RendererConfig { + width: config.default_window_width.get(), + height: config.default_window_height.get(), + instance_capacity: config.sprite_manager_capacity, + fullscreen: false, + vsync: config.vsync, + }; + + Renderer::new(window, config) +} + +fn main() { + let console = Console::new(26009) + .block_on() + .expect("The console should not fail to start"); + profile::set_profiler(console.logger()); + + std::env::set_current_dir(std::env::current_exe().unwrap().parent().unwrap()).unwrap(); + let config = File::open("game.json").unwrap(); + let config: Config = serde_json::from_reader(config).unwrap(); + + let sprites = sprite_manager(&config); + let scripts = script_manager(&config); + let mut window = window(&config); + + window.wait_for_resume(); + + let mut renderer = renderer(&config, &window); + window.set_visible(true); + + window.run(move |window, event| match event { + Some(WindowEvent::RedrawRequest) => { + renderer.render_frame(); + profile::finish_frame(); + } + Some(WindowEvent::CloseRequest) => { + std::process::exit(0); + } + Some(_) => (), + None => window.request_redraw(), + }) +} diff --git a/sys/alligator_backend.lib b/sys/alligator_backend.lib new file mode 100644 index 0000000..1b79670 Binary files /dev/null and b/sys/alligator_backend.lib differ diff --git a/sys/build.rs b/sys/build.rs index c33a20f..8efc265 100644 --- a/sys/build.rs +++ b/sys/build.rs @@ -1,8 +1,8 @@ -fn main() { - let out_dir = std::env::var("OUT_DIR").unwrap(); - eprintln!("{out_dir}"); - println!("cargo:rustc-link-lib=d3d11"); - println!("cargo:rustc-link-search=native=./"); - println!("cargo:rustc-link-lib-static=alligator_backend"); - println!("cargo:rerun-if-changed=alligator_backend.lib"); -} +fn main() { + let out_dir = std::env::var("OUT_DIR").unwrap(); + eprintln!("{out_dir}"); + println!("cargo:rustc-link-lib=d3d11"); + println!("cargo:rustc-link-search=native=./"); + println!("cargo:rustc-link-lib-static=alligator_backend"); + println!("cargo:rerun-if-changed=alligator_backend.lib"); +} diff --git a/sys/src/renderer.rs b/sys/src/renderer.rs index 05d111b..a4dab20 100644 --- a/sys/src/renderer.rs +++ b/sys/src/renderer.rs @@ -1,49 +1,49 @@ -use crate::{RendererConfig, Vertex, Window}; - -pub struct Renderer { - ptr: *mut (), -} - -impl Drop for Renderer { - fn drop(&mut self) { - unsafe { crate::destroy_renderer(self.ptr) } - } -} - -impl Renderer { - pub fn new(window: &Window, config: RendererConfig) -> Self { - let ptr = unsafe { crate::new_renderer(config, window.ptr) }; - Self { ptr } - } - - pub fn resize(&mut self, width: u32, height: u32) { - unsafe { crate::resize_renderer(self.ptr, width, height) } - } - - pub fn set_vsync(&mut self, vsync: bool) { - unsafe { crate::set_vsync(self.ptr, vsync) } - } - - pub fn create_vertex_buffer(&mut self, vertices: &[Vertex]) { - assert!(vertices.len() < (u32::MAX as usize), "Too many triangles!"); - let ptr = vertices.as_ptr(); - let len = vertices.len(); - unsafe { crate::create_vertex_buffer(self.ptr, len as u32, ptr) } - } - - pub fn set_camera( - &mut self, - x: f32, - y: f32, - zoom: f32, - rotation: f32, - width: f32, - height: f32, - ) { - unsafe { crate::set_camera(self.ptr, x, y, zoom, rotation, width, height) } - } - - pub fn render_frame(&mut self) { - unsafe { crate::render_frame(self.ptr) } - } -} +use crate::{RendererConfig, Vertex, Window}; + +pub struct Renderer { + ptr: *mut (), +} + +impl Drop for Renderer { + fn drop(&mut self) { + unsafe { crate::destroy_renderer(self.ptr) } + } +} + +impl Renderer { + pub fn new(window: &Window, config: RendererConfig) -> Self { + let ptr = unsafe { crate::new_renderer(config, window.ptr) }; + Self { ptr } + } + + pub fn resize(&mut self, width: u32, height: u32) { + unsafe { crate::resize_renderer(self.ptr, width, height) } + } + + pub fn set_vsync(&mut self, vsync: bool) { + unsafe { crate::set_vsync(self.ptr, vsync) } + } + + pub fn create_vertex_buffer(&mut self, vertices: &[Vertex]) { + assert!(vertices.len() < (u32::MAX as usize), "Too many triangles!"); + let ptr = vertices.as_ptr(); + let len = vertices.len(); + unsafe { crate::create_vertex_buffer(self.ptr, len as u32, ptr) } + } + + pub fn set_camera( + &mut self, + x: f32, + y: f32, + zoom: f32, + rotation: f32, + width: f32, + height: f32, + ) { + unsafe { crate::set_camera(self.ptr, x, y, zoom, rotation, width, height) } + } + + pub fn render_frame(&mut self) { + unsafe { crate::render_frame(self.ptr) } + } +} diff --git a/sys/src/window.rs b/sys/src/window.rs index 19de5e7..f9a8832 100644 --- a/sys/src/window.rs +++ b/sys/src/window.rs @@ -1,116 +1,116 @@ -use std::ffi::{c_void, CString}; -use std::ops::ControlFlow; - -use crate::{CWindowConfig, CWindowEvent}; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct WindowConfig { - pub title: String, - pub default_width: u32, - pub default_height: u32, - pub default_x: u32, - pub default_y: u32, - pub visible: bool, - pub borderless_fullscreen: bool, -} - -pub struct Window { - pub(crate) ptr: *mut (), -} - -pub enum WindowEvent { - Other = 1, - CloseRequest, - ScaleFactorChange, - Resume, - RedrawRequest, -} - -impl Drop for Window { - fn drop(&mut self) { - unsafe { crate::destroy_window(self.ptr) } - } -} - -impl Window { - pub fn new(config: WindowConfig) -> Self { - let title = CString::new(config.title.as_bytes()).unwrap(); - let config = CWindowConfig { - default_width: config.default_width, - default_height: config.default_height, - default_x: config.default_x, - default_y: config.default_y, - visible: config.visible, - borderless_fullscreen: config.borderless_fullscreen, - title: title.as_ptr(), - }; - - let window = unsafe { crate::create_window(config) }; - - Self { ptr: window } - } - - pub fn set_visible(&mut self, visible: bool) { - unsafe { crate::set_visible(self.ptr, visible) } - } - - pub fn set_title(&mut self, title: &str) { - let string = CString::new(title.to_string().as_bytes()).unwrap(); - let bytes = string.as_ptr(); - unsafe { crate::set_title(self.ptr, bytes) } - } - - pub fn resize(&mut self, width: u32, height: u32) { - unsafe { crate::resize_window(self.ptr, width, height) } - } - - pub fn set_fullscreen(&mut self, fullscreen: bool) { - unsafe { crate::set_fullscreen(self.ptr, fullscreen) } - } - - fn translate_event(event: CWindowEvent) -> Option { - let event = match event { - CWindowEvent::AboutToWait => return None, - CWindowEvent::Other => WindowEvent::Other, - CWindowEvent::CloseRequest => WindowEvent::CloseRequest, - CWindowEvent::ScaleFactorChange => WindowEvent::ScaleFactorChange, - CWindowEvent::Resume => WindowEvent::Resume, - CWindowEvent::RedrawRequest => WindowEvent::RedrawRequest, - }; - Some(event) - } - - pub fn wait_for_event(&self) { - unsafe { crate::wait_for_event(self.ptr) } - } - - pub fn pop_event(&self) -> bool { - unsafe { crate::pop_event(self.ptr) } - } - - pub fn wait_for_resume(&mut self) { - unsafe { crate::wait_for_resume(self.ptr) } - } - - pub fn run(&mut self, mut handler: impl FnMut(&mut Window, Option)) -> ! { - let window_ptr = self.ptr; - - unsafe { - let closure = |c_event: CWindowEvent| { - handler(self, Self::translate_event(c_event)); - }; - let closure_data: Box> = Box::new(Box::new(closure)); - crate::set_event_handler(window_ptr, Box::into_raw(closure_data) as *mut _); - } - - loop { - if !self.pop_event() { - unsafe { crate::run_event_handler(window_ptr, CWindowEvent::AboutToWait) }; - } - } - } - - pub fn request_redraw(&mut self) { - unsafe { crate::request_redraw(self.ptr) } - } -} +use std::ffi::{c_void, CString}; +use std::ops::ControlFlow; + +use crate::{CWindowConfig, CWindowEvent}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct WindowConfig { + pub title: String, + pub default_width: u32, + pub default_height: u32, + pub default_x: u32, + pub default_y: u32, + pub visible: bool, + pub borderless_fullscreen: bool, +} + +pub struct Window { + pub(crate) ptr: *mut (), +} + +pub enum WindowEvent { + Other = 1, + CloseRequest, + ScaleFactorChange, + Resume, + RedrawRequest, +} + +impl Drop for Window { + fn drop(&mut self) { + unsafe { crate::destroy_window(self.ptr) } + } +} + +impl Window { + pub fn new(config: WindowConfig) -> Self { + let title = CString::new(config.title.as_bytes()).unwrap(); + let config = CWindowConfig { + default_width: config.default_width, + default_height: config.default_height, + default_x: config.default_x, + default_y: config.default_y, + visible: config.visible, + borderless_fullscreen: config.borderless_fullscreen, + title: title.as_ptr(), + }; + + let window = unsafe { crate::create_window(config) }; + + Self { ptr: window } + } + + pub fn set_visible(&mut self, visible: bool) { + unsafe { crate::set_visible(self.ptr, visible) } + } + + pub fn set_title(&mut self, title: &str) { + let string = CString::new(title.to_string().as_bytes()).unwrap(); + let bytes = string.as_ptr(); + unsafe { crate::set_title(self.ptr, bytes) } + } + + pub fn resize(&mut self, width: u32, height: u32) { + unsafe { crate::resize_window(self.ptr, width, height) } + } + + pub fn set_fullscreen(&mut self, fullscreen: bool) { + unsafe { crate::set_fullscreen(self.ptr, fullscreen) } + } + + fn translate_event(event: CWindowEvent) -> Option { + let event = match event { + CWindowEvent::AboutToWait => return None, + CWindowEvent::Other => WindowEvent::Other, + CWindowEvent::CloseRequest => WindowEvent::CloseRequest, + CWindowEvent::ScaleFactorChange => WindowEvent::ScaleFactorChange, + CWindowEvent::Resume => WindowEvent::Resume, + CWindowEvent::RedrawRequest => WindowEvent::RedrawRequest, + }; + Some(event) + } + + pub fn wait_for_event(&self) { + unsafe { crate::wait_for_event(self.ptr) } + } + + pub fn pop_event(&self) -> bool { + unsafe { crate::pop_event(self.ptr) } + } + + pub fn wait_for_resume(&mut self) { + unsafe { crate::wait_for_resume(self.ptr) } + } + + pub fn run(&mut self, mut handler: impl FnMut(&mut Window, Option)) -> ! { + let window_ptr = self.ptr; + + unsafe { + let closure = |c_event: CWindowEvent| { + handler(self, Self::translate_event(c_event)); + }; + let closure_data: Box> = Box::new(Box::new(closure)); + crate::set_event_handler(window_ptr, Box::into_raw(closure_data) as *mut _); + } + + loop { + if !self.pop_event() { + unsafe { crate::run_event_handler(window_ptr, CWindowEvent::AboutToWait) }; + } + } + } + + pub fn request_redraw(&mut self) { + unsafe { crate::request_redraw(self.ptr) } + } +} diff --git a/todos.txt b/todos.txt index 8880a50..a5d94ed 100644 --- a/todos.txt +++ b/todos.txt @@ -1,2 +1,2 @@ -Use DirectX12 directly -GPU accelerated vector graphics +Use DirectX12 directly +GPU accelerated vector graphics -- cgit v1.2.3