mochi_rs/imports/
core.rs

1extern crate alloc;
2
3use alloc::string::String;
4use alloc::vec::Vec;
5
6use super::html::Node;
7
8use super::error::{Result, MochiError, PtrCastError};
9
10type MutRawBufPtr = *mut u8;
11type RawBufPtr = *const u8;
12pub(crate) type HostPtr = i32;
13
14#[link(wasm_import_module = "core")]
15extern "C" {
16    pub(crate) fn copy(ptr: HostPtr) -> HostPtr;
17    pub(crate) fn destroy(ptr: HostPtr);
18
19    fn create_array() -> HostPtr;
20    fn create_obj() -> HostPtr;
21    fn create_string(buf_raw_ptr: RawBufPtr, buf_len: i32) -> HostPtr;
22    fn create_bool(value: bool) -> HostPtr;
23    fn create_float(value: f64) -> HostPtr;
24    fn create_int(value: i64) -> HostPtr;
25    fn create_error() -> HostPtr;
26
27    pub(crate) fn ptr_kind(ptr: HostPtr) -> Kind;
28
29    fn string_len(ptr: HostPtr) -> i32;
30    fn read_string(ptr: HostPtr, buf_raw_ptr: MutRawBufPtr, buf_len: i32);
31    fn read_int(ptr: HostPtr) -> i64;
32    fn read_float(ptr: HostPtr) -> f64;
33    fn read_bool(ptr: HostPtr) -> bool;
34
35    fn obj_len(ptr: HostPtr) -> usize;
36    fn obj_get(ptr: HostPtr, key_raw_ptr: RawBufPtr, len: usize) -> HostPtr;
37    fn obj_set(ptr: HostPtr, key_raw_ptr: RawBufPtr, len: usize, value_ptr: HostPtr);
38    fn obj_remove(ptr: HostPtr, key_raw_ptr: RawBufPtr, len: usize);
39    fn obj_keys(ptr: HostPtr) -> HostPtr;
40    fn obj_values(ptr: HostPtr) -> HostPtr;
41
42    fn array_len(ptr: HostPtr) -> i32;
43    fn array_get(ptr: HostPtr, idx: i32) -> i32;
44    fn array_set(ptr: HostPtr, idx: i32, value_ptr: i32);
45    fn array_append(ptr: HostPtr, value_pre: i32);
46    fn array_remove(ptr: HostPtr, idx: i32);
47}
48
49/// Prints a message to the Aidoku logs.
50pub fn print<T: AsRef<str>>(string: T) {
51    let string = string.as_ref();
52    extern "C" {
53        fn print(string: *const u8, size: usize);
54    }
55    unsafe {
56        print(string.as_ptr(), string.len());
57    }
58}
59
60#[repr(C)]
61#[derive(PartialEq, Eq, Debug, Clone, Copy)]
62pub enum Kind {
63    Unknown,
64    Null,
65    Object,
66    Array,
67    String,
68    Number,
69    Bool,
70    Node
71}
72
73/// References a pointer from the host.
74/// 
75/// It could be casted to any type, although you should 
76/// only cast if you are sure of the type of cast.
77///
78/// `From<T>` implementations are used to turn a rust value to a host pointer. It allocates 
79/// the value in the host.
80///
81/// `Into<T>` implementations are used to convert a host's value pointer to a rust type.
82/// 
83#[derive(Debug)]
84pub struct PtrRef(HostPtr);
85
86impl PtrRef {
87    #[inline]
88    pub fn new(ptr: HostPtr) -> Self {
89        PtrRef(ptr)
90    }
91
92    #[inline]
93    pub fn pointer(&self) -> HostPtr {
94        self.0
95    }
96
97    #[inline]
98    pub fn kind(&self) -> Kind {
99        unsafe { ptr_kind(self.0) }
100    }
101
102    #[inline]
103    pub fn is_none(&self) -> bool {
104        self.kind() == Kind::Null
105    }
106
107    #[inline]
108    pub fn is_some(&self) -> bool {
109        !self.is_none()
110    }
111
112    pub fn as_string(&self) -> Result<String> {
113        match self.kind() {
114            Kind::String => {
115                let str_len = unsafe { string_len(self.0) };
116                let mut buf = alloc::vec::Vec::with_capacity(str_len as usize);
117                unsafe { 
118                    read_string(self.0, buf.as_mut_ptr(), str_len);
119                    buf.set_len(str_len as usize);
120                }
121                String::from_utf8(buf).map_err(|_| MochiError::from(PtrCastError::Utf8NotValid))        
122            },
123            Kind::Null => {
124                Err(MochiError::from(PtrCastError::NullPointer))
125            },
126            _ => {
127                Err(MochiError::from(PtrCastError::NotString))
128            }
129        }
130    }
131
132    pub fn as_object(self) -> Result<ObjectRef> {
133        match self.kind() {
134            Kind::Object => {
135                Ok(ObjectRef(self))
136            },
137            Kind::Null => {
138                Err(MochiError::from(PtrCastError::NullPointer))
139            },
140            _ => {
141                Err(MochiError::from(PtrCastError::NotObject))
142            }
143        }
144    }
145
146    pub fn as_array(self) -> Result<ArrayRef> {
147        match self.kind() {
148            Kind::Array => {
149                Ok(ArrayRef::from(self))
150            },
151            Kind::Null => {
152                Err(MochiError::from(PtrCastError::NullPointer))
153            },
154            _ => {
155                Err(MochiError::from(PtrCastError::NotArray))
156            }
157        }
158    }
159
160    pub fn as_int(&self) -> Result<i64> {
161        match self.kind() {
162            Kind::Number | Kind::Bool | Kind::String => {
163                Ok(unsafe { read_int(self.0) })    
164            },
165            Kind::Null => {
166                Err(MochiError::from(PtrCastError::NullPointer))
167            },
168            _ => {
169                Err(MochiError::from(PtrCastError::NotNumber))
170            }
171        }
172    }
173
174    pub fn as_float(&self) -> Result<f64> {
175        match self.kind() {
176            Kind::Number | Kind::Bool | Kind::String => {
177                Ok(unsafe { read_float(self.0) })    
178            },
179            Kind::Null => {
180                Err(MochiError::from(PtrCastError::NullPointer))
181            },
182            _ => {
183                Err(MochiError::from(PtrCastError::NotNumber))
184            }
185        }
186    }
187
188    pub fn as_bool(&self) -> Result<bool> {
189        match self.kind() {
190            Kind::Number | Kind::Bool => {
191                Ok(unsafe { read_bool(self.0) })
192            },
193            Kind::Null => {
194                Err(MochiError::from(PtrCastError::NullPointer))
195            },
196            _ => {
197                Err(MochiError::from(PtrCastError::NotNumber))
198            }
199        }
200    }
201
202    /// Cast the ValueRef to a [Node](crate::html::Node).
203    pub fn as_node(&self) -> Result<Node> {
204        match self.kind() {
205            Kind::Node => {
206                Ok(unsafe { Node::from(self.0) })
207            },
208            Kind::Null => {
209                Err(MochiError::from(PtrCastError::NullPointer))
210            },
211            _ => {
212                Err(MochiError::from(PtrCastError::NotArray))
213            }
214        }
215    }
216}
217
218impl Clone for PtrRef {
219    fn clone(&self) -> Self {
220        Self(unsafe { copy(self.0) })
221    }
222}
223
224impl Drop for PtrRef {
225    fn drop(&mut self) {
226        unsafe { destroy(self.0) }
227    }
228}
229
230impl From<i32> for PtrRef {
231    fn from(value: i32) -> Self {
232        PtrRef(unsafe { create_int(value as i64) })
233    }
234}
235
236impl From<i64> for PtrRef {
237    fn from(value: i64) -> Self {
238        PtrRef(unsafe { create_int(value as i64) })
239    }
240}
241
242impl From<f32> for PtrRef {
243    fn from(value: f32) -> Self {
244        PtrRef(unsafe { create_float(value as f64) })
245    }
246}
247
248impl From<f64> for PtrRef {
249    fn from(value: f64) -> Self {
250        PtrRef(unsafe { create_float(value as f64) })
251    }
252}
253
254impl From<bool> for PtrRef {
255    fn from(value: bool) -> Self {
256        PtrRef(unsafe { create_bool(value) })
257    }
258}
259
260impl From<String> for PtrRef {
261    fn from(value: String) -> Self {
262        PtrRef( unsafe { create_string(value.as_ptr(), value.len() as i32) })
263    }
264}
265
266impl From<&str> for PtrRef {
267    fn from(value: &str) -> Self {
268        PtrRef( unsafe { create_string(value.as_ptr(), value.len() as i32) })
269    }
270}
271
272impl<T> From<Result<T>> for PtrRef where PtrRef: From<T> {
273    fn from(value: Result<T>) -> Self {
274        match value {
275            Result::Ok(val) => val.into(),
276            Result::Err(_) => PtrRef(unsafe { create_error() }),
277        }
278    }
279}
280
281impl Into<String> for PtrRef {
282    fn into(self) -> String {
283        self.as_string().unwrap_or_default()
284    }
285}
286
287/// A key-value object, typically shown as a dictionary
288/// 
289/// 
290pub struct ObjectRef(PtrRef);
291
292impl ObjectRef {
293    pub fn new() -> Self {
294        let ptr: i32 = unsafe { create_obj() };
295        Self(PtrRef::new(ptr))
296    }
297
298    #[inline]
299    pub fn len(&self) -> usize {
300        unsafe { obj_len(self.0.0) }
301    }
302
303    #[inline]
304    pub fn is_empty(&self) -> bool {
305        self.len() == 0
306    }
307
308    pub fn get(&self, key: &str) -> PtrRef {
309        let ptr = unsafe { obj_get(self.0.0, key.as_ptr(), key.len()) };
310        PtrRef::new(ptr)
311    }
312
313    #[inline]
314    pub fn set(&mut self, key: &str, value: PtrRef) {
315        unsafe { obj_set(self.0.0, key.as_ptr(), key.len(), value.0) }
316    }
317
318    #[inline]
319    pub fn remove(&mut self, key: &str) {
320        unsafe { obj_remove(self.0.0, key.as_ptr(), key.len()) }
321    }
322
323    pub fn keys(&self) -> ArrayRef {
324        let rid = unsafe { obj_keys(self.0 .0) };
325        ArrayRef::from(PtrRef::new(rid))
326    }
327
328    pub fn values(&self) -> ArrayRef {
329        let rid = unsafe { obj_values(self.0 .0) };
330        ArrayRef::from(PtrRef::new(rid))
331    }
332
333    #[inline]
334    pub fn ptr(&self) -> i32 {
335        self.0.pointer()
336    } 
337}
338
339impl Clone for ObjectRef {
340    fn clone(&self) -> Self {
341        Self(PtrRef::new(unsafe { copy(self.0.0) }))
342    }
343}
344
345impl Default for ObjectRef {
346    fn default() -> Self {
347        Self::new()
348    }
349}
350
351#[derive(Debug)]
352pub struct ArrayRef(
353    PtrRef,
354    i32,
355    i32
356);
357
358impl ArrayRef {
359    pub fn new() -> Self {
360        let pid = unsafe { create_array() };
361        Self(PtrRef::new(pid), 0, 0)
362    }
363
364    #[inline]
365    pub fn len(&self) -> i32 {
366        unsafe { array_len(self.0.0) }
367    }
368
369    #[inline]
370    pub fn is_empty(&self) -> bool {
371        self.len() == 0
372    }
373
374    pub fn get(&self, index: i32) -> PtrRef {
375        let rid = unsafe { array_get(self.0.0, index) };
376        PtrRef::new(rid)
377    }
378
379    #[inline]
380    pub fn set(&mut self, index: i32, object: PtrRef) {
381        unsafe { array_set(self.0.0, index, object.0) };
382    }
383
384    #[inline]
385    pub fn insert(&mut self, value: PtrRef) {
386        unsafe { array_append(self.0.0, value.0) };
387        self.2 += 1;
388    }
389
390    #[inline]
391    pub fn remove(&mut self, index: i32) {
392        unsafe { array_remove(self.0.0, index) };
393        self.2 -= 1;
394    }
395
396    #[inline]
397    pub fn ptr(&self) -> i32 {
398        self.0.pointer()
399    }
400}
401
402impl Iterator for ArrayRef {
403    type Item = PtrRef;
404
405    fn next(&mut self) -> Option<Self::Item> {
406        if self.1 > self.2 || self.2 == i32::MAX {
407            return None;
408        }
409        let value_ref = self.get(self.1);
410        self.1 += 1;
411        Some(value_ref)
412    }
413}
414
415impl DoubleEndedIterator for ArrayRef {
416    fn next_back(&mut self) -> Option<Self::Item> {
417        if self.1 > self.2 || self.2 == i32::MAX {
418            return None;
419        }
420        let value_ref = self.get(self.2);
421        self.2 = self.2.wrapping_sub(1);
422        Some(value_ref)
423    }
424}
425
426impl FromIterator<PtrRef> for ArrayRef {
427    fn from_iter<T: IntoIterator<Item = PtrRef>>(iter: T) -> Self {
428        let mut array = Self::new();
429        for value in iter {
430            array.insert(value);
431        }
432        array
433    }
434}
435
436impl From<PtrRef> for ArrayRef {
437    fn from(ptr: PtrRef) -> Self {
438        let length = unsafe { array_len(ptr.0) };
439        Self(ptr, 0, length.wrapping_sub(1))
440    }
441}
442
443impl<T: Into<PtrRef>> From<Vec<T>> for ArrayRef {
444    fn from(value: Vec<T>) -> Self {
445        let mut array = ArrayRef::new();
446        for item in value {
447            array.insert(item.into())
448        }
449        array
450    }
451}
452
453impl Clone for ArrayRef {
454    fn clone(&self) -> Self {
455        let ptr = unsafe { copy(self.0.0) };
456        Self(PtrRef::new(ptr), self.1, self.2)
457    }
458}
459
460impl Default for ArrayRef {
461    fn default() -> Self {
462        Self::new()
463    }
464}