1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use core::cell::{Ref, RefCell, RefMut};
use core::ffi::CStr;

use alloc::ffi::CString;
use alloc::string::{String, ToString};
use alloc::vec::Vec;

use crate::{GlobalInstance, MemoryInstance, Result};
use tinywasm_types::WasmValue;

// This module essentially contains the public APIs to interact with the data stored in the store

/// A reference to a memory instance
#[derive(Debug)]
pub struct MemoryRef<'a> {
    pub(crate) instance: Ref<'a, MemoryInstance>,
}

/// A borrowed reference to a memory instance
#[derive(Debug)]
pub struct MemoryRefMut<'a> {
    pub(crate) instance: RefMut<'a, MemoryInstance>,
}

impl<'a> MemoryRefLoad for MemoryRef<'a> {
    /// Load a slice of memory
    fn load(&self, offset: usize, len: usize) -> Result<&[u8]> {
        self.instance.load(offset, len)
    }
}

impl<'a> MemoryRefLoad for MemoryRefMut<'a> {
    /// Load a slice of memory
    fn load(&self, offset: usize, len: usize) -> Result<&[u8]> {
        self.instance.load(offset, len)
    }
}

impl MemoryRef<'_> {
    /// Load a slice of memory
    pub fn load(&self, offset: usize, len: usize) -> Result<&[u8]> {
        self.instance.load(offset, len)
    }

    /// Load a slice of memory as a vector
    pub fn load_vec(&self, offset: usize, len: usize) -> Result<Vec<u8>> {
        self.load(offset, len).map(|x| x.to_vec())
    }
}

impl MemoryRefMut<'_> {
    /// Load a slice of memory
    pub fn load(&self, offset: usize, len: usize) -> Result<&[u8]> {
        self.instance.load(offset, len)
    }

    /// Load a slice of memory as a vector
    pub fn load_vec(&self, offset: usize, len: usize) -> Result<Vec<u8>> {
        self.load(offset, len).map(|x| x.to_vec())
    }

    /// Grow the memory by the given number of pages
    pub fn grow(&mut self, delta_pages: i32) -> Option<i32> {
        self.instance.grow(delta_pages)
    }

    /// Get the current size of the memory in pages
    pub fn page_count(&mut self) -> usize {
        self.instance.page_count()
    }

    /// Copy a slice of memory to another place in memory
    pub fn copy_within(&mut self, src: usize, dst: usize, len: usize) -> Result<()> {
        self.instance.copy_within(src, dst, len)
    }

    /// Fill a slice of memory with a value
    pub fn fill(&mut self, offset: usize, len: usize, val: u8) -> Result<()> {
        self.instance.fill(offset, len, val)
    }

    /// Store a slice of memory
    pub fn store(&mut self, offset: usize, len: usize, data: &[u8]) -> Result<()> {
        self.instance.store(offset, len, data)
    }
}

#[doc(hidden)]
pub trait MemoryRefLoad {
    fn load(&self, offset: usize, len: usize) -> Result<&[u8]>;
    fn load_vec(&self, offset: usize, len: usize) -> Result<Vec<u8>> {
        self.load(offset, len).map(|x| x.to_vec())
    }
}

/// Convenience methods for loading strings from memory
pub trait MemoryStringExt: MemoryRefLoad {
    /// Load a C-style string from memory
    fn load_cstr(&self, offset: usize, len: usize) -> Result<&CStr> {
        let bytes = self.load(offset, len)?;
        CStr::from_bytes_with_nul(bytes).map_err(|_| crate::Error::Other("Invalid C-style string".to_string()))
    }

    /// Load a C-style string from memory, stopping at the first nul byte
    fn load_cstr_until_nul(&self, offset: usize, max_len: usize) -> Result<&CStr> {
        let bytes = self.load(offset, max_len)?;
        CStr::from_bytes_until_nul(bytes).map_err(|_| crate::Error::Other("Invalid C-style string".to_string()))
    }

    /// Load a UTF-8 string from memory
    fn load_string(&self, offset: usize, len: usize) -> Result<String> {
        let bytes = self.load(offset, len)?;
        String::from_utf8(bytes.to_vec()).map_err(|_| crate::Error::Other("Invalid UTF-8 string".to_string()))
    }

    /// Load a C-style string from memory
    fn load_cstring(&self, offset: usize, len: usize) -> Result<CString> {
        Ok(CString::from(self.load_cstr(offset, len)?))
    }

    /// Load a C-style string from memory, stopping at the first nul byte
    fn load_cstring_until_nul(&self, offset: usize, max_len: usize) -> Result<CString> {
        Ok(CString::from(self.load_cstr_until_nul(offset, max_len)?))
    }

    /// Load a JavaScript-style utf-16 string from memory
    fn load_js_string(&self, offset: usize, len: usize) -> Result<String> {
        let bytes = self.load(offset, len)?;
        let mut string = String::new();
        for i in 0..(len / 2) {
            let c = u16::from_le_bytes([bytes[i * 2], bytes[i * 2 + 1]]);
            string.push(
                char::from_u32(c as u32).ok_or_else(|| crate::Error::Other("Invalid UTF-16 string".to_string()))?,
            );
        }
        Ok(string)
    }
}

impl MemoryStringExt for MemoryRef<'_> {}
impl MemoryStringExt for MemoryRefMut<'_> {}

/// A reference to a global instance
#[derive(Debug)]
pub struct GlobalRef {
    pub(crate) instance: RefCell<GlobalInstance>,
}

impl GlobalRef {
    /// Get the value of the global
    pub fn get(&self) -> WasmValue {
        self.instance.borrow().get()
    }

    /// Set the value of the global
    pub fn set(&self, val: WasmValue) -> Result<()> {
        self.instance.borrow_mut().set(val)
    }
}