1use crate::{ffi, instance::function::AsFunc, FuncRef, Function};
4use core::ffi::c_void;
5use std::ffi::CString;
6use wasmedge_types::ValType;
7
8#[derive(Debug, Clone)]
9pub(crate) struct WasmEdgeLimit {
10 min: u32,
11 max: Option<u32>,
12 shared: bool,
13}
14impl WasmEdgeLimit {
15 pub(crate) fn new(min: u32, max: Option<u32>, shared: bool) -> Self {
16 Self { min, max, shared }
17 }
18
19 pub(crate) fn min(&self) -> u32 {
20 self.min
21 }
22
23 pub(crate) fn max(&self) -> Option<u32> {
24 self.max
25 }
26
27 pub(crate) fn shared(&self) -> bool {
28 self.shared
29 }
30}
31impl WasmEdgeLimit {
32 pub(crate) fn to_context(&self) -> *mut ffi::WasmEdge_LimitContext {
38 unsafe {
39 match self.max {
40 Some(max) => ffi::WasmEdge_LimitCreateWithMax(
41 self.min as u64,
42 max as u64,
43 false, self.shared,
45 ),
46 None => ffi::WasmEdge_LimitCreate(self.min as u64, false),
47 }
48 }
49 }
50
51 pub(crate) fn from_context(ctx: *const ffi::WasmEdge_LimitContext) -> Self {
53 unsafe {
54 let min = ffi::WasmEdge_LimitGetMin(ctx) as u32;
55 let max = if ffi::WasmEdge_LimitHasMax(ctx) {
56 Some(ffi::WasmEdge_LimitGetMax(ctx) as u32)
57 } else {
58 None
59 };
60 let shared = ffi::WasmEdge_LimitIsShared(ctx);
61 Self { min, max, shared }
62 }
63 }
64}
65
66#[derive(Debug)]
68pub struct WasmEdgeString {
69 inner: InnerWasmEdgeString,
70}
71impl Drop for WasmEdgeString {
72 fn drop(&mut self) {
73 unsafe { ffi::WasmEdge_StringDelete(self.inner.0) }
74 }
75}
76impl WasmEdgeString {
77 pub(crate) fn as_raw(&self) -> ffi::WasmEdge_String {
78 self.inner.0
79 }
80
81 pub unsafe fn into_raw(self) -> ffi::WasmEdge_String {
85 let s = self.inner.0;
86 std::mem::forget(self);
87 s
88 }
89
90 pub unsafe fn from_raw(s: ffi::WasmEdge_String) -> Self {
94 Self {
95 inner: InnerWasmEdgeString(s),
96 }
97 }
98}
99impl<T: AsRef<str>> From<T> for WasmEdgeString {
100 fn from(s: T) -> Self {
101 let ctx = if s.as_ref().contains('\0') {
102 let buffer = s.as_ref().as_bytes();
103 unsafe {
104 ffi::WasmEdge_StringCreateByBuffer(buffer.as_ptr() as *const _, buffer.len() as u32)
105 }
106 } else {
107 let cs = CString::new(s.as_ref()).expect(
108 "Failed to create a CString: the supplied bytes contain an internal 0 byte",
109 );
110 unsafe { ffi::WasmEdge_StringCreateByCString(cs.as_ptr()) }
111 };
112
113 Self {
114 inner: InnerWasmEdgeString(ctx),
115 }
116 }
117}
118impl PartialEq for WasmEdgeString {
119 fn eq(&self, other: &Self) -> bool {
120 unsafe { ffi::WasmEdge_StringIsEqual(self.inner.0, other.inner.0) }
121 }
122}
123impl Eq for WasmEdgeString {}
124
125impl AsRef<ffi::WasmEdge_String> for WasmEdgeString {
126 fn as_ref(&self) -> &ffi::WasmEdge_String {
127 &self.inner.0
128 }
129}
130impl AsMut<ffi::WasmEdge_String> for WasmEdgeString {
131 fn as_mut(&mut self) -> &mut ffi::WasmEdge_String {
132 &mut self.inner.0
133 }
134}
135
136impl From<&WasmEdgeString> for String {
137 fn from(s: &WasmEdgeString) -> Self {
138 s.as_ref().into()
139 }
140}
141impl From<&WasmEdgeString> for &std::ffi::CStr {
142 fn from(s: &WasmEdgeString) -> Self {
143 s.as_ref().into()
144 }
145}
146impl From<WasmEdgeString> for String {
147 fn from(s: WasmEdgeString) -> Self {
148 s.as_ref().into()
149 }
150}
151impl From<WasmEdgeString> for &std::ffi::CStr {
152 fn from(s: WasmEdgeString) -> Self {
153 s.as_ref().into()
154 }
155}
156
157impl From<&ffi::WasmEdge_String> for String {
158 fn from(s: &ffi::WasmEdge_String) -> Self {
159 let cstr = unsafe { std::slice::from_raw_parts(s.Buf as *mut u8, s.Length as usize) };
160 String::from_utf8(cstr.to_vec()).unwrap_or_default()
161 }
162}
163impl From<&ffi::WasmEdge_String> for &std::ffi::CStr {
164 fn from(s: &ffi::WasmEdge_String) -> Self {
165 unsafe { std::ffi::CStr::from_ptr(s.Buf as *const _) }
166 }
167}
168impl From<ffi::WasmEdge_String> for String {
169 fn from(s: ffi::WasmEdge_String) -> Self {
170 (&s).into()
171 }
172}
173impl From<ffi::WasmEdge_String> for &std::ffi::CStr {
174 fn from(s: ffi::WasmEdge_String) -> Self {
175 (&s).into()
176 }
177}
178
179#[derive(Debug)]
180pub(crate) struct InnerWasmEdgeString(pub(crate) ffi::WasmEdge_String);
181unsafe impl Send for InnerWasmEdgeString {}
182unsafe impl Sync for InnerWasmEdgeString {}
183
184#[derive(Debug, Clone, Copy)]
186pub struct WasmValue {
187 ctx: ffi::WasmEdge_Value,
188 ty: ValType,
189}
190impl WasmValue {
191 pub fn as_raw(&self) -> ffi::WasmEdge_Value {
193 self.ctx
194 }
195
196 pub fn ty(&self) -> ValType {
198 self.ty
199 }
200
201 pub fn from_i32(val: i32) -> Self {
207 Self {
208 ctx: unsafe { ffi::WasmEdge_ValueGenI32(val) },
209 ty: ValType::I32,
210 }
211 }
212
213 pub fn to_i32(&self) -> i32 {
215 unsafe { ffi::WasmEdge_ValueGetI32(self.ctx) }
216 }
217
218 pub fn from_i64(val: i64) -> Self {
224 Self {
225 ctx: unsafe { ffi::WasmEdge_ValueGenI64(val) },
226 ty: ValType::I64,
227 }
228 }
229
230 pub fn to_i64(&self) -> i64 {
232 unsafe { ffi::WasmEdge_ValueGetI64(self.ctx) }
233 }
234
235 pub fn from_f32(val: f32) -> Self {
241 Self {
242 ctx: unsafe { ffi::WasmEdge_ValueGenF32(val) },
243 ty: ValType::F32,
244 }
245 }
246
247 pub fn to_f32(&self) -> f32 {
249 unsafe { ffi::WasmEdge_ValueGetF32(self.ctx) }
250 }
251
252 pub fn from_f64(val: f64) -> Self {
258 Self {
259 ctx: unsafe { ffi::WasmEdge_ValueGenF64(val) },
260 ty: ValType::F64,
261 }
262 }
263
264 pub fn to_f64(&self) -> f64 {
266 unsafe { ffi::WasmEdge_ValueGetF64(self.ctx) }
267 }
268
269 pub fn from_v128(val: i128) -> Self {
275 Self {
276 ctx: unsafe { ffi::WasmEdge_ValueGenV128(val) },
277 ty: ValType::V128,
278 }
279 }
280
281 pub fn to_v128(&self) -> i128 {
283 unsafe { ffi::WasmEdge_ValueGetV128(self.ctx) }
284 }
285
286 pub fn is_null_ref(&self) -> bool {
288 unsafe { ffi::WasmEdge_ValueIsNullRef(self.ctx) }
289 }
290
291 pub fn from_func_ref<Func: AsFunc>(func_ref: &Func) -> Self {
299 Self {
300 ctx: unsafe { ffi::WasmEdge_ValueGenFuncRef(func_ref.get_func_raw()) },
301 ty: ValType::FuncRef,
302 }
303 }
304
305 pub fn func_ref(&self) -> Option<FuncRef<&Self>> {
309 unsafe {
310 match ffi::WasmEdge_ValueIsNullRef(self.ctx) {
311 true => None,
312 false => {
313 let ctx = ffi::WasmEdge_ValueGetFuncRef(self.ctx);
314 let f = Function::from_raw(ctx as _);
315 Some(FuncRef::create_from_ref(
316 std::mem::ManuallyDrop::new(f),
317 self,
318 ))
319 }
320 }
321 }
322 }
323
324 pub fn from_extern_ref<T>(extern_obj: &mut T) -> Self {
333 let ptr = extern_obj as *mut T as *mut c_void;
334 Self {
335 ctx: unsafe { ffi::WasmEdge_ValueGenExternRef(ptr) },
336 ty: ValType::ExternRef,
337 }
338 }
339
340 pub fn null_extern_ref() -> Self {
346 Self {
347 ctx: unsafe { ffi::WasmEdge_ValueGenExternRef(std::ptr::null_mut()) },
348 ty: ValType::ExternRef,
349 }
350 }
351
352 pub fn extern_ref<T>(&self) -> Option<&T> {
356 unsafe {
357 match ffi::WasmEdge_ValueIsNullRef(self.ctx) {
358 true => None,
359 false => {
360 let ptr = ffi::WasmEdge_ValueGetExternRef(self.ctx);
361 let x = ptr as *mut T;
362 Some(&*x)
363 }
364 }
365 }
366 }
367}
368impl From<ffi::WasmEdge_Value> for WasmValue {
369 fn from(raw_val: ffi::WasmEdge_Value) -> Self {
370 let ty = raw_val.Type.into();
371 Self { ctx: raw_val, ty }
372 }
373}
374
375impl From<ffi::WasmEdge_ValType> for ValType {
376 fn from(value: ffi::WasmEdge_ValType) -> Self {
377 unsafe {
378 if ffi::WasmEdge_ValTypeIsI32(value) {
379 ValType::I32
380 } else if ffi::WasmEdge_ValTypeIsI64(value) {
381 ValType::I64
382 } else if ffi::WasmEdge_ValTypeIsF32(value) {
383 ValType::F32
384 } else if ffi::WasmEdge_ValTypeIsF64(value) {
385 ValType::F64
386 } else if ffi::WasmEdge_ValTypeIsV128(value) {
387 ValType::V128
388 } else if ffi::WasmEdge_ValTypeIsRef(value) {
389 if ffi::WasmEdge_ValTypeIsFuncRef(value) {
390 ValType::FuncRef
391 } else if ffi::WasmEdge_ValTypeIsExternRef(value) {
392 ValType::ExternRef
393 } else {
394 log::warn!(
395 "capi unsupport WasmEdge_RefType `{:x}`",
396 u64::from_be_bytes(value.Data)
397 );
398 ValType::UnsupportedRef
399 }
400 } else {
401 log::warn!(
402 "unknown WasmEdge_ValType `{:x}`",
403 u64::from_be_bytes(value.Data)
404 );
405 ValType::UnsupportedRef
406 }
407 }
408 }
409}
410impl From<ValType> for ffi::WasmEdge_ValType {
411 fn from(value: ValType) -> Self {
412 unsafe {
413 match value {
414 ValType::I32 => ffi::WasmEdge_ValTypeGenI32(),
415 ValType::I64 => ffi::WasmEdge_ValTypeGenI64(),
416 ValType::F32 => ffi::WasmEdge_ValTypeGenF32(),
417 ValType::F64 => ffi::WasmEdge_ValTypeGenF64(),
418 ValType::V128 => ffi::WasmEdge_ValTypeGenV128(),
419 ValType::FuncRef => ffi::WasmEdge_ValTypeGenFuncRef(),
420 ValType::ExternRef => ffi::WasmEdge_ValTypeGenExternRef(),
421 ValType::UnsupportedRef => ffi::WasmEdge_ValTypeGenExternRef(),
423 }
424 }
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431 #[cfg(unix)]
432 use crate::{Table, TableType};
433 use std::{
434 sync::{Arc, Mutex},
435 thread,
436 };
437 #[cfg(unix)]
438 use wasmedge_types::RefType;
439
440 #[test]
441 #[cfg(unix)]
442 fn test_types_value() {
443 let val = WasmValue::from_i32(1314);
445 assert_eq!(val.ty(), ValType::I32);
446
447 let val = WasmValue::from_i64(1314);
449 assert_eq!(val.ty(), ValType::I64);
450
451 let val = WasmValue::from_f32(13.14);
453 assert_eq!(val.ty(), ValType::F32);
454
455 let val = WasmValue::from_f64(13.14);
457 assert_eq!(val.ty(), ValType::F64);
458
459 let val = WasmValue::from_v128(1314);
461 assert_eq!(val.ty(), ValType::V128);
462
463 let ty = TableType::new(RefType::FuncRef, 10, Some(20));
465 let result = Table::create(ty);
466 assert!(result.is_ok());
467 let mut table = result.unwrap();
468 let value = WasmValue::from_extern_ref(&mut table);
469 assert_eq!(value.ty(), ValType::ExternRef);
470 assert!(value.extern_ref::<Table>().is_some());
471
472 let val1 = WasmValue::from_i32(1314);
473 let val2 = WasmValue::from_i32(1314);
474 assert_eq!(val1.to_i32(), val2.to_i32());
475 }
476
477 #[test]
478 #[cfg(unix)]
479 fn test_types_value_send() {
480 let val_i32 = WasmValue::from_i32(1314);
482 let val_i64 = WasmValue::from_i64(1314);
484 let val_f32 = WasmValue::from_f32(13.14);
486 let val_f64 = WasmValue::from_f64(13.14);
488 let val_v128 = WasmValue::from_v128(1314);
490
491 let ty = TableType::new(RefType::FuncRef, 10, Some(20));
493 let result = Table::create(ty);
494 assert!(result.is_ok());
495 let mut table = result.unwrap();
496 let val_extern_ref = WasmValue::from_extern_ref(&mut table);
497
498 let handle = thread::spawn(move || {
499 let val_i32_c = val_i32;
500 assert_eq!(val_i32_c.ty(), ValType::I32);
501
502 let val_i64_c = val_i64;
503 assert_eq!(val_i64_c.ty(), ValType::I64);
504
505 let val_f32_c = val_f32;
506 assert_eq!(val_f32_c.ty(), ValType::F32);
507
508 let val_f64_c = val_f64;
509 assert_eq!(val_f64_c.ty(), ValType::F64);
510
511 let val_v128_c = val_v128;
512 assert_eq!(val_v128_c.ty(), ValType::V128);
513
514 let val_extern_ref_c = val_extern_ref;
515 assert_eq!(val_extern_ref_c.ty(), ValType::ExternRef);
516 assert!(val_extern_ref_c.extern_ref::<Table>().is_some());
517 });
518
519 handle.join().unwrap();
520 }
521
522 #[test]
523 #[cfg(unix)]
524 fn test_types_value_sync() {
525 let val_i32 = Arc::new(Mutex::new(WasmValue::from_i32(1314)));
527 let val_i32_cloned = Arc::clone(&val_i32);
528
529 let val_i64 = Arc::new(Mutex::new(WasmValue::from_i64(1314)));
531 let val_i64_cloned = Arc::clone(&val_i64);
532
533 let val_f32 = Arc::new(Mutex::new(WasmValue::from_f32(13.14)));
535 let val_f32_cloned = Arc::clone(&val_f32);
536
537 let val_f64 = Arc::new(Mutex::new(WasmValue::from_f64(13.14)));
539 let val_f64_cloned = Arc::clone(&val_f64);
540
541 let val_v128 = Arc::new(Mutex::new(WasmValue::from_v128(1314)));
543 let val_v128_cloned = Arc::clone(&val_v128);
544
545 let ty = TableType::new(RefType::FuncRef, 10, Some(20));
547 let result = Table::create(ty);
548 assert!(result.is_ok());
549 let mut table = result.unwrap();
550 let val_extern_ref = Arc::new(Mutex::new(WasmValue::from_extern_ref(&mut table)));
551 let val_extern_ref_cloned = Arc::clone(&val_extern_ref);
552
553 let handle = thread::spawn(move || {
554 let result = val_i32_cloned.lock();
555 assert!(result.is_ok());
556 let val_i32_c = result.unwrap();
557 assert_eq!(val_i32_c.ty(), ValType::I32);
558
559 let result = val_i64_cloned.lock();
560 assert!(result.is_ok());
561 let val_i64_c = result.unwrap();
562 assert_eq!(val_i64_c.ty(), ValType::I64);
563
564 let result = val_f32_cloned.lock();
565 assert!(result.is_ok());
566 let val_f32_c = result.unwrap();
567 assert_eq!(val_f32_c.ty(), ValType::F32);
568
569 let result = val_f64_cloned.lock();
570 assert!(result.is_ok());
571 let val_f64_c = result.unwrap();
572 assert_eq!(val_f64_c.ty(), ValType::F64);
573
574 let result = val_v128_cloned.lock();
575 assert!(result.is_ok());
576 let val_v128_c = result.unwrap();
577 assert_eq!(val_v128_c.ty(), ValType::V128);
578
579 let result = val_extern_ref_cloned.lock();
580 assert!(result.is_ok());
581 let val_extern_ref_c = result.unwrap();
582 assert_eq!(val_extern_ref_c.ty(), ValType::ExternRef);
583 assert!(val_extern_ref_c.extern_ref::<Table>().is_some());
584 });
585
586 handle.join().unwrap();
587 }
588
589 #[test]
590 fn test_types_string() {
591 let s: WasmEdgeString = "hello".into();
592 let t: WasmEdgeString = "hello".into();
593 assert_eq!(s, t);
594
595 let s: WasmEdgeString = "hello".into();
596 let t = String::from(s);
597 assert_eq!(t, "hello");
598
599 let s: WasmEdgeString = "hello".into();
600 let t: WasmEdgeString = "hello\0".into();
601 assert_ne!(s, t);
602
603 let s: WasmEdgeString = "hello\0".into();
604 let t = String::from(s);
605 assert_eq!(t, "hello\0");
606
607 let s: WasmEdgeString = "he\0llo\0".into();
608 let t = String::from(s);
609 assert_eq!(t, "he\0llo\0");
610 }
611
612 #[test]
613 fn test_types_string_send() {
614 let s: WasmEdgeString = "hello".into();
615
616 let handle = thread::spawn(move || {
617 let t: WasmEdgeString = "hello".into();
618 assert_eq!(s, t);
619 });
620
621 handle.join().unwrap();
622 }
623
624 #[test]
625 fn test_types_string_sync() {
626 let s: WasmEdgeString = "hello".into();
627 let p = Arc::new(Mutex::new(s));
628
629 let s_cloned = Arc::clone(&p);
630 let handle = thread::spawn(move || {
631 let result = s_cloned.lock();
632 assert!(result.is_ok());
633 let s = result.unwrap();
634
635 let t: WasmEdgeString = "hello".into();
636 assert_eq!(*s, t);
637 });
638
639 handle.join().unwrap();
640 }
641}