1use lotus_bindgen_macros::lotus_bindgen;
2use serde::{de::DeserializeOwned, Serialize};
3
4#[no_mangle]
5pub extern "C" fn allocate(size: u32) -> u32 {
6 unsafe {
7 std::alloc::alloc(std::alloc::Layout::from_size_align(size as usize, 8).unwrap()) as u32
8 }
9}
10
11#[no_mangle]
12pub extern "C" fn deallocate(ptr: u32, size: u32) {
13 unsafe {
14 std::alloc::dealloc(
15 ptr as *mut u8,
16 std::alloc::Layout::from_size_align(size as usize, 8).unwrap(),
17 )
18 }
19}
20
21extern "C" {
22 #[lotus_bindgen]
23 pub fn is_rc() -> bool;
24}
25
26pub mod assets {
27 #[link(wasm_import_module = "assets")]
28 extern "C" {
29 pub fn preload(id: u64);
30 }
31}
32
33pub mod time {
34 #[link(wasm_import_module = "time")]
35 extern "C" {
36 pub fn delta_f64() -> f64;
37 pub fn ticks_alive() -> u64;
38 }
39}
40
41pub mod log {
42 #[link(wasm_import_module = "log")]
43 extern "C" {
44 pub fn write(level: i32, message: u64);
45 }
46}
47
48pub mod messages {
49 #[link(wasm_import_module = "messages")]
50 extern "C" {
51 pub fn take() -> u64;
52 pub fn send(target: u64, message: u64);
53 }
54}
55
56pub mod textures {
57 #[link(wasm_import_module = "textures")]
58 extern "C" {
59 pub fn create(options: u64) -> u32;
60 pub fn add_action(texture: u32, options: u64);
61 pub fn get_pixel(texture: u32, x: u32, y: u32) -> u32;
62 pub fn apply_to(texture: u32, name: u64);
63 pub fn flush_actions(texture: u32) -> u32;
64 pub fn dispose(texture: u32);
65 }
66}
67
68pub mod var {
69 #[link(wasm_import_module = "var")]
70 extern "C" {
71 pub fn get_i64(name: u64) -> i64;
72 pub fn set_i64(name: u64, value: i64);
73 pub fn get_f64(name: u64) -> f64;
74 pub fn set_f64(name: u64, value: f64);
75 pub fn get_string(name: u64) -> u64;
76 pub fn set_string(name: u64, value: u64);
77 pub fn get_bool(name: u64) -> i32;
78 pub fn set_bool(name: u64, value: i32);
79 pub fn get_content_id(name: u64) -> u64;
80 pub fn set_content_id(name: u64, value: u64);
81 }
82}
83
84pub mod rand {
85 #[link(wasm_import_module = "rand")]
86 extern "C" {
87 pub fn f64() -> f64;
88 pub fn u64(min: u64, max: u64) -> u64;
90 pub fn seed(seed: u64);
91 pub fn random_seed();
92 }
93}
94
95pub mod gizmo {
96 #[link(wasm_import_module = "gizmo")]
97 extern "C" {
98 pub fn draw(gizmo: u64);
99 }
100}
101
102pub mod action {
103 #[link(wasm_import_module = "action")]
104 extern "C" {
105 pub fn register(action: u64);
106 pub fn state(action: u64) -> u64;
107 }
108}
109
110pub mod input {
111 #[link(wasm_import_module = "input")]
112 extern "C" {
113 pub fn mouse_delta() -> u64;
114 }
115}
116
117pub mod font {
118 #[link(wasm_import_module = "font")]
119 extern "C" {
120 pub fn bitmap_font_properties(font: u64) -> u64;
121
122 pub fn text_len(font: u64, text: u64, letter_spacing: i32) -> i32;
125 }
126}
127
128pub trait FromFfi {
129 type FfiType;
130 fn from_ffi(ffi: Self::FfiType) -> Self;
131}
132
133impl FromFfi for String {
134 type FfiType = u64;
135 fn from_ffi(ffi: Self::FfiType) -> Self {
136 FfiObject::from_packed(ffi).deserialize()
137 }
138}
139
140enum FfiObjectData {
141 Boxed(Box<[u8]>),
142 Raw(*mut u8, usize),
143}
144
145impl FfiObjectData {
146 fn as_slice(&self) -> &[u8] {
147 match self {
148 Self::Boxed(data) => data,
149 Self::Raw(ptr, len) => unsafe { std::slice::from_raw_parts(*ptr, *len) },
150 }
151 }
152}
153
154impl Drop for FfiObject {
155 fn drop(&mut self) {
156 match self.data {
157 FfiObjectData::Boxed(_) => {}
158 FfiObjectData::Raw(ptr, len) => unsafe {
159 std::alloc::dealloc(ptr, std::alloc::Layout::from_size_align(len, 8).unwrap())
160 },
161 }
162 }
163}
164
165pub struct FfiObject {
166 data: FfiObjectData,
167}
168
169impl FfiObject {
170 pub fn new<T: Serialize>(value: &T) -> Self {
171 let data = rmp_serde::to_vec_named(value)
172 .expect("Failed to serialize value")
173 .into_boxed_slice();
174
175 Self {
176 data: FfiObjectData::Boxed(data),
177 }
178 }
179
180 pub fn deserialize<T: DeserializeOwned>(&self) -> T {
181 rmp_serde::from_slice(self.data.as_slice()).expect("Failed to deserialize value")
182 }
183
184 pub fn packed(&self) -> u64 {
185 let ptr = self.data.as_slice().as_ptr() as u32;
186 let len = self.data.as_slice().len() as u32;
187
188 let mut packed = [0u8; 8];
189 packed[..4].copy_from_slice(&ptr.to_be_bytes());
190 packed[4..].copy_from_slice(&len.to_be_bytes());
191
192 u64::from_be_bytes(packed)
193 }
194
195 pub fn from_packed(packed: u64) -> Self {
196 let packed = packed.to_be_bytes();
197 let ptr = u32::from_be_bytes(packed[..4].try_into().unwrap());
198 let len = u32::from_be_bytes(packed[4..].try_into().unwrap());
199
200 Self {
201 data: FfiObjectData::Raw(ptr as *mut u8, len as usize),
202 }
203 }
204}