1use super::{FFIResult, Ptr, Rid};
3use crate::{
4 AidokuError,
5 alloc::{String, Vec},
6};
7use core::ptr::null;
8use serde::{Serialize, de::DeserializeOwned};
9
10#[link(wasm_import_module = "std")]
11unsafe extern "C" {
12 pub(crate) fn destroy(rid: Rid);
13
14 pub(crate) fn buffer_len(rid: Rid) -> FFIResult;
15
16 #[link_name = "read_buffer"]
17 fn _read_buffer(rid: Rid, buf: *mut u8, len: usize) -> FFIResult;
18
19 #[link_name = "current_date"]
20 fn _current_date() -> f64;
21
22 fn utc_offset() -> i64;
23
24 #[link_name = "parse_date"]
25 fn _parse_date(
26 string_ptr: *const u8,
27 string_len: usize,
28 format_ptr: *const u8,
29 format_len: usize,
30 locale_ptr: *const u8,
31 locale_len: usize,
32 timezone_ptr: *const u8,
33 timezone_len: usize,
34 ) -> f64;
35}
36
37#[link(wasm_import_module = "env")]
39unsafe extern "C" {
40 #[link_name = "print"]
44 fn _print(string: *const u8, size: usize);
45
46 #[link_name = "sleep"]
47 fn _sleep(seconds: i32);
48
49 #[link_name = "send_partial_result"]
50 fn _send_partial_result(value: Ptr);
51}
52
53#[derive(PartialEq, Eq, Debug, Clone, Copy)]
55pub enum StdError {
56 InvalidDescriptor,
57 InvalidBufferSize,
58 FailedMemoryWrite,
59 InvalidString,
60 InvalidDateString,
61}
62
63impl StdError {
64 fn from(value: i32) -> Option<Self> {
65 match value {
66 -1 => Some(Self::InvalidDescriptor),
67 -2 => Some(Self::InvalidBufferSize),
68 -3 => Some(Self::FailedMemoryWrite),
69 -4 => Some(Self::InvalidString),
70 -5 => Some(Self::InvalidDateString),
71 _ => None,
72 }
73 }
74}
75
76pub fn print<T: AsRef<str>>(string: T) {
78 let string = string.as_ref();
79 unsafe {
80 _print(string.as_ptr(), string.len());
81 }
82}
83
84pub fn sleep(seconds: i32) {
86 unsafe {
87 _sleep(seconds);
88 }
89}
90
91pub(crate) unsafe fn encode<T: Serialize>(result: &T) -> Ptr {
99 let mut bytes = ::postcard::to_allocvec(result).unwrap();
100 bytes.splice(0..0, [0, 0, 0, 0, 0, 0, 0, 0]);
101 let len_bytes = (bytes.len() as i32).to_le_bytes();
102 bytes[0..4].copy_from_slice(&len_bytes);
103 let cap_bytes = (bytes.capacity() as i32).to_le_bytes();
104 bytes[4..8].copy_from_slice(&cap_bytes);
105 let ptr = bytes.as_ptr() as Ptr;
106 ::core::mem::forget(bytes);
107 ptr
108}
109
110pub unsafe fn free_result(ptr: Ptr) {
118 let ptr = ptr as *const u8;
119 let (len, cap) = unsafe {
120 let cap_and_len = ::core::slice::from_raw_parts(ptr, 8);
121 let len = i32::from_le_bytes([
122 cap_and_len[0],
123 cap_and_len[1],
124 cap_and_len[2],
125 cap_and_len[3],
126 ]);
127 let cap = i32::from_le_bytes([
128 cap_and_len[4],
129 cap_and_len[5],
130 cap_and_len[6],
131 cap_and_len[7],
132 ]);
133 if len == -1 {
134 let real_len_slice = ::core::slice::from_raw_parts(ptr.offset(8), 4);
135 let real_len = i32::from_le_bytes([
136 real_len_slice[0],
137 real_len_slice[1],
138 real_len_slice[2],
139 real_len_slice[3],
140 ]);
141 (real_len, cap)
142 } else {
143 (len, cap)
144 }
145 };
146 let original_vec: Vec<u8> =
147 unsafe { Vec::from_raw_parts(ptr as *mut u8, len as usize, cap as usize) };
148 drop(original_vec);
149}
150
151pub fn send_partial_result<T: Serialize>(value: &T) {
159 let value_ptr = unsafe { encode(value) };
160 unsafe {
161 _send_partial_result(value_ptr);
162 }
163 unsafe { free_result(value_ptr) };
164}
165
166pub fn current_date() -> i64 {
168 unsafe { _current_date() as i64 }
169}
170
171pub fn read<T: DeserializeOwned>(rid: Rid) -> Result<T, AidokuError> {
176 read_buffer(rid)
177 .and_then(|buffer| postcard::from_bytes(&buffer).ok())
178 .ok_or(AidokuError::DeserializeError)
179}
180
181pub fn read_string(rid: Rid) -> Option<String> {
186 let buffer = read_buffer(rid)?;
187 let string = String::from_utf8(buffer).unwrap_or_default();
188 if string.is_empty() {
189 None
190 } else {
191 Some(string)
192 }
193}
194
195pub(crate) fn read_string_and_destroy(rid: Rid) -> Option<String> {
196 let buffer = read_buffer(rid);
197 unsafe { destroy(rid) };
198 let buffer = buffer?;
199 let string = String::from_utf8(buffer).unwrap_or_default();
200 if string.is_empty() {
201 None
202 } else {
203 Some(string)
204 }
205}
206
207pub(crate) fn read_buffer(rid: Rid) -> Option<Vec<u8>> {
209 let len = unsafe { buffer_len(rid) };
210 if len < 0 {
211 return None;
212 }
213 let len = len as usize;
214 let mut buffer = Vec::with_capacity(len);
215 let error = unsafe { _read_buffer(rid, buffer.as_mut_ptr(), len) };
216 if error != 0 {
219 return None;
220 }
221 unsafe { buffer.set_len(len) };
222 Some(buffer)
223}
224
225pub fn get_utc_offset() -> i64 {
226 unsafe { utc_offset() }
227}
228
229pub fn parse_date<T: AsRef<str>, U: AsRef<str>>(date_str: T, format: U) -> Option<i64> {
241 let string = date_str.as_ref();
242 let format = format.as_ref();
243 let timezone = "UTC";
244 let result = unsafe {
245 _parse_date(
246 string.as_ptr(),
247 string.len(),
248 format.as_ptr(),
249 format.len(),
250 null(),
251 0,
252 timezone.as_ptr(),
253 timezone.len(),
254 )
255 };
256 if StdError::from(result as i32).is_some() {
257 return None;
258 }
259 Some(result as i64)
260}
261
262pub fn parse_local_date<T: AsRef<str>, U: AsRef<str>>(date_str: T, format: U) -> Option<i64> {
266 let string = date_str.as_ref();
267 let format = format.as_ref();
268 let timezone = "current";
269 let result = unsafe {
270 _parse_date(
271 string.as_ptr(),
272 string.len(),
273 format.as_ptr(),
274 format.len(),
275 null(),
276 0,
277 timezone.as_ptr(),
278 timezone.len(),
279 )
280 };
281 if StdError::from(result as i32).is_some() {
282 return None;
283 }
284 Some(result as i64)
285}
286
287pub fn parse_date_with_options<T: AsRef<str>, U: AsRef<str>, V: AsRef<str>, W: AsRef<str>>(
292 date_str: T,
293 format: U,
294 locale: V,
295 timezone: W,
296) -> Option<i64> {
297 let string = date_str.as_ref();
298 let format = format.as_ref();
299 let locale = locale.as_ref();
300 let timezone = timezone.as_ref();
301 let result = unsafe {
302 _parse_date(
303 string.as_ptr(),
304 string.len(),
305 format.as_ptr(),
306 format.len(),
307 locale.as_ptr(),
308 locale.len(),
309 timezone.as_ptr(),
310 timezone.len(),
311 )
312 };
313 if StdError::from(result as i32).is_some() {
314 return None;
315 }
316 Some(result as i64)
317}