1use crate::{ffi, types::WasmEdgeLimit, utils::check, WasmEdgeResult};
9use wasmedge_types::error::{MemError, WasmEdgeError};
10
11#[derive(Debug)]
13pub struct Memory {
14 pub(crate) inner: InnerMemory,
15}
16impl Memory {
17 pub fn create(ty: &wasmedge_types::MemoryType) -> WasmEdgeResult<Self> {
28 let ty: MemType = ty.into();
29 let ctx = unsafe { ffi::WasmEdge_MemoryInstanceCreate(ty.inner.0 as *const _) };
30
31 match ctx.is_null() {
32 true => Err(Box::new(WasmEdgeError::Mem(MemError::Create))),
33 false => Ok(Memory {
34 inner: InnerMemory(ctx),
35 }),
36 }
37 }
38
39 pub fn ty(&self) -> WasmEdgeResult<wasmedge_types::MemoryType> {
46 let ty_ctx = unsafe { ffi::WasmEdge_MemoryInstanceGetMemoryType(self.inner.0) };
47 match ty_ctx.is_null() {
48 true => Err(Box::new(WasmEdgeError::Mem(MemError::Type))),
49 false => {
50 let ty = std::mem::ManuallyDrop::new(MemType {
51 inner: InnerMemType(ty_ctx as *mut _),
52 });
53 Ok((&*ty).into())
54 }
55 }
56 }
57
58 pub fn get_data(&self, offset: u32, len: u32) -> WasmEdgeResult<Vec<u8>> {
71 let mut data = Vec::with_capacity(len as usize);
72 unsafe {
73 check(ffi::WasmEdge_MemoryInstanceGetData(
74 self.inner.0,
75 data.as_mut_ptr(),
76 offset.into(),
77 len.into(),
78 ))?;
79 data.set_len(len as usize);
80 }
81
82 Ok(data.into_iter().collect())
83 }
84
85 pub fn set_data(&mut self, data: impl AsRef<[u8]>, offset: u32) -> WasmEdgeResult<()> {
99 unsafe {
100 check(ffi::WasmEdge_MemoryInstanceSetData(
101 self.inner.0,
102 data.as_ref().as_ptr(),
103 offset.into(),
104 data.as_ref().len() as u64,
105 ))
106 }
107 }
108
109 pub unsafe fn data_pointer(&self, offset: u32, len: u32) -> WasmEdgeResult<*const u8> {
127 let ptr = unsafe {
128 ffi::WasmEdge_MemoryInstanceGetPointerConst(self.inner.0, offset.into(), len.into())
129 };
130 match ptr.is_null() {
131 true => Err(Box::new(WasmEdgeError::Mem(MemError::ConstPtr))),
132 false => Ok(ptr),
133 }
134 }
135
136 pub unsafe fn data_pointer_mut(&mut self, offset: u32, len: u32) -> WasmEdgeResult<*mut u8> {
153 let ptr = unsafe {
154 ffi::WasmEdge_MemoryInstanceGetPointer(self.inner.0, offset.into(), len.into())
155 };
156 match ptr.is_null() {
157 true => Err(Box::new(WasmEdgeError::Mem(MemError::MutPtr))),
158 false => Ok(ptr),
159 }
160 }
161
162 pub fn size(&self) -> u32 {
164 unsafe { ffi::WasmEdge_MemoryInstanceGetPageSize(self.inner.0) as u32 }
165 }
166
167 pub fn grow(&mut self, count: u32) -> WasmEdgeResult<()> {
178 unsafe {
179 check(ffi::WasmEdge_MemoryInstanceGrowPage(
180 self.inner.0,
181 count.into(),
182 ))
183 }
184 }
185
186 pub unsafe fn as_ptr(&self) -> *const ffi::WasmEdge_MemoryInstanceContext {
191 self.inner.0
192 }
193}
194impl Drop for Memory {
195 fn drop(&mut self) {
196 unsafe { ffi::WasmEdge_MemoryInstanceDelete(self.inner.0) };
197 }
198}
199
200impl Memory {
201 pub fn get_ref<T: Sized>(&self, offset: usize) -> Option<&T> {
202 unsafe {
203 let r = std::mem::size_of::<T>();
204 let ptr = self.data_pointer(offset as u32, r as u32).ok()?;
205 ptr.cast::<T>().as_ref()
206 }
207 }
208
209 pub fn slice<T: Sized>(&self, offset: usize, len: usize) -> Option<&[T]> {
210 unsafe {
211 let r = std::mem::size_of::<T>() * len;
212 let ptr = self.data_pointer(offset as u32, r as u32).ok()? as *const T;
213 Some(std::slice::from_raw_parts(ptr, len))
214 }
215 }
216
217 pub fn get_ref_mut<T: Sized>(&mut self, offset: usize) -> Option<&mut T> {
218 unsafe {
219 let r = std::mem::size_of::<T>();
220 let ptr = self.data_pointer_mut(offset as u32, r as u32).ok()?;
221 ptr.cast::<T>().as_mut()
222 }
223 }
224
225 #[allow(clippy::mut_from_ref)]
226 pub fn mut_slice<T: Sized>(&self, offset: usize, len: usize) -> Option<&mut [T]> {
227 unsafe {
228 let r = std::mem::size_of::<T>() * len;
229 let ptr = self.data_pointer(offset as u32, r as u32).ok()? as *mut T;
230 Some(std::slice::from_raw_parts_mut(ptr, len))
231 }
232 }
233
234 pub fn write<T: Sized>(&mut self, offset: usize, data: T) -> Option<()> {
235 let p = self.get_ref_mut(offset)?;
236 *p = data;
237 Some(())
238 }
239}
240
241#[derive(Debug)]
242pub(crate) struct InnerMemory(pub(crate) *mut ffi::WasmEdge_MemoryInstanceContext);
243unsafe impl Send for InnerMemory {}
244unsafe impl Sync for InnerMemory {}
245
246#[derive(Debug)]
248pub(crate) struct MemType {
249 pub(crate) inner: InnerMemType,
250}
251impl MemType {
252 pub(crate) fn create(min: u32, max: Option<u32>, shared: bool) -> WasmEdgeResult<Self> {
273 if shared && max.is_none() {
274 return Err(Box::new(WasmEdgeError::Mem(MemError::CreateSharedType)));
275 }
276 let limit_ctx = WasmEdgeLimit::new(min, max, shared).to_context();
279 let ctx = unsafe { ffi::WasmEdge_MemoryTypeCreate(limit_ctx) };
280 unsafe { ffi::WasmEdge_LimitDelete(limit_ctx) };
281 match ctx.is_null() {
282 true => Err(Box::new(WasmEdgeError::MemTypeCreate)),
283 false => Ok(Self {
284 inner: InnerMemType(ctx),
285 }),
286 }
287 }
288
289 pub(crate) fn min(&self) -> u32 {
291 let limit = unsafe { ffi::WasmEdge_MemoryTypeGetLimit(self.inner.0) };
292 let limit = WasmEdgeLimit::from_context(limit);
293 limit.min()
294 }
295
296 pub(crate) fn max(&self) -> Option<u32> {
298 let limit = unsafe { ffi::WasmEdge_MemoryTypeGetLimit(self.inner.0) };
299 let limit = WasmEdgeLimit::from_context(limit);
300 limit.max()
301 }
302
303 pub(crate) fn shared(&self) -> bool {
305 let limit = unsafe { ffi::WasmEdge_MemoryTypeGetLimit(self.inner.0) };
306 let limit = WasmEdgeLimit::from_context(limit);
307 limit.shared()
308 }
309}
310impl Drop for MemType {
311 fn drop(&mut self) {
312 unsafe { ffi::WasmEdge_MemoryTypeDelete(self.inner.0) }
313 }
314}
315impl From<&wasmedge_types::MemoryType> for MemType {
316 fn from(ty: &wasmedge_types::MemoryType) -> Self {
317 MemType::create(ty.minimum(), ty.maximum(), ty.shared()).expect(
318 "[wasmedge-sys] Failed to convert wasmedge_types::MemoryType into wasmedge_sys::MemType.",
319 )
320 }
321}
322impl From<wasmedge_types::MemoryType> for MemType {
323 fn from(ty: wasmedge_types::MemoryType) -> Self {
324 (&ty).into()
325 }
326}
327impl From<&MemType> for wasmedge_types::MemoryType {
328 fn from(ty: &MemType) -> Self {
329 wasmedge_types::MemoryType::new(ty.min(), ty.max(), ty.shared()).expect(
330 "[wasmedge-sys] Failed to convert wasmedge_sys::MemType into wasmedge_types::MemoryType."
331 )
332 }
333}
334
335#[derive(Debug)]
336pub(crate) struct InnerMemType(pub(crate) *mut ffi::WasmEdge_MemoryTypeContext);
337unsafe impl Send for InnerMemType {}
338unsafe impl Sync for InnerMemType {}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343 use std::thread;
344 use wasmedge_types::error::{CoreError, CoreExecutionError, WasmEdgeError};
345
346 #[test]
347 fn test_memory_type() {
348 let result = MemType::create(0, Some(u32::MAX), false);
350 assert!(result.is_ok());
351 let ty = result.unwrap();
352 assert!(!ty.inner.0.is_null());
353 assert_eq!(ty.min(), 0);
354 assert_eq!(ty.max(), Some(u32::MAX));
355
356 let result = MemType::create(10, Some(101), false);
358 assert!(result.is_ok());
359 let ty = result.unwrap();
360 assert!(!ty.inner.0.is_null());
361 assert_eq!(ty.min(), 10);
362 assert_eq!(ty.max(), Some(101));
363 }
364
365 #[test]
366 #[allow(clippy::assertions_on_result_states)]
367 fn test_memory_grow() {
368 let result = wasmedge_types::MemoryType::new(10, Some(20), false);
370 assert!(result.is_ok());
371 let ty = result.unwrap();
372 let result = Memory::create(&ty);
373 assert!(result.is_ok());
374 let mut mem = result.unwrap();
375 assert!(!mem.inner.0.is_null());
376
377 let result = mem.ty();
379 assert!(result.is_ok());
380 let ty = result.unwrap();
381 assert_eq!(ty.minimum(), 10);
383 assert_eq!(ty.maximum(), Some(20));
384
385 let count = mem.size();
387 assert_eq!(count, 10);
388
389 let result = mem.grow(10);
391 assert!(result.is_ok());
392 assert_eq!(mem.size(), 20);
393
394 let result = mem.grow(1);
396 assert!(result.is_err());
397 }
398
399 #[test]
400 #[allow(clippy::assertions_on_result_states)]
401 fn test_memory_data() {
402 let result = wasmedge_types::MemoryType::new(1, Some(2), false);
404 assert!(result.is_ok());
405 let ty = result.unwrap();
406 let result = Memory::create(&ty);
407 assert!(result.is_ok());
408 let mut mem = result.unwrap();
409 assert!(!mem.inner.0.is_null());
410
411 let count = mem.size();
413 assert_eq!(count, 1);
414
415 let result = mem.get_data(0, 10);
417 assert!(result.is_ok());
418 let data = result.unwrap();
419 assert_eq!(data, vec![0; 10]);
420
421 let result = mem.set_data(vec![1; 10], 10);
423 assert!(result.is_ok());
424 let result = mem.get_data(10, 10);
426 assert!(result.is_ok());
427 let data = result.unwrap();
428 assert_eq!(data, vec![1; 10]);
429
430 let result = mem.set_data(vec![1; 10], u32::pow(2, 16) - 9);
432 assert!(result.is_err());
433 assert_eq!(
434 result.unwrap_err(),
435 Box::new(WasmEdgeError::Core(CoreError::Execution(
436 CoreExecutionError::MemoryOutOfBounds
437 )))
438 );
439
440 let result = mem.grow(1);
442 assert!(result.is_ok());
443 assert_eq!(mem.size(), 2);
444 let result = mem.set_data(vec![1; 10], u32::pow(2, 16) - 9);
445 assert!(result.is_ok());
446 }
447
448 #[test]
449 fn test_memory_send() {
450 {
451 let result = wasmedge_types::MemoryType::new(10, Some(101), false);
452 assert!(result.is_ok());
453 let ty = result.unwrap();
454
455 let handle = thread::spawn(move || {
456 assert_eq!(ty.minimum(), 10);
457 assert_eq!(ty.maximum(), Some(101));
458 });
459
460 handle.join().unwrap()
461 }
462
463 {
464 let result = wasmedge_types::MemoryType::new(10, Some(20), false);
466 assert!(result.is_ok());
467 let ty = result.unwrap();
468 let result = Memory::create(&ty);
469 assert!(result.is_ok());
470 let mem = result.unwrap();
471 assert!(!mem.inner.0.is_null());
472
473 let handle = thread::spawn(move || {
474 let result = mem.ty();
476 assert!(result.is_ok());
477 let ty = result.unwrap();
478 assert_eq!(ty.minimum(), 10);
480 assert_eq!(ty.maximum(), Some(20));
481
482 let count = mem.size();
484 assert_eq!(count, 10);
485 });
486
487 handle.join().unwrap()
488 }
489 }
490
491 #[test]
492 fn test_memory_sync() {
493 let result = wasmedge_types::MemoryType::new(10, Some(20), false);
495 assert!(result.is_ok());
496 let ty = result.unwrap();
497 let result = Memory::create(&ty);
498 assert!(result.is_ok());
499 let mem = result.unwrap();
500 assert!(!mem.inner.0.is_null());
501 let mem = &mem;
502
503 std::thread::scope(|s| {
504 let _ = s
505 .spawn(|| {
506 let result = mem.ty();
508 assert!(result.is_ok());
509 let ty = result.unwrap();
510 assert_eq!(ty.minimum(), 10);
512 assert_eq!(ty.maximum(), Some(20));
513
514 let count = mem.size();
516 assert_eq!(count, 10);
517 })
518 .join();
519 })
520 }
521}