github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/examples/allocation/rust/testdata/greet.rs (about) 1 extern crate alloc; 2 extern crate core; 3 extern crate wee_alloc; 4 5 use alloc::vec::Vec; 6 use std::mem::MaybeUninit; 7 use std::slice; 8 9 /// Prints a greeting to the console using [`log`]. 10 fn greet(name: &String) { 11 log(&["wasm >> ", &greeting(name)].concat()); 12 } 13 14 /// Gets a greeting for the name. 15 fn greeting(name: &String) -> String { 16 return ["Hello, ", &name, "!"].concat(); 17 } 18 19 /// Logs a message to the console using [`_log`]. 20 fn log(message: &String) { 21 unsafe { 22 let (ptr, len) = string_to_ptr(message); 23 _log(ptr, len); 24 } 25 } 26 27 #[link(wasm_import_module = "env")] 28 extern "C" { 29 /// WebAssembly import which prints a string (linear memory offset, 30 /// byteCount) to the console. 31 /// 32 /// Note: This is not an ownership transfer: Rust still owns the pointer 33 /// and ensures it isn't deallocated during this call. 34 #[link_name = "log"] 35 fn _log(ptr: u32, size: u32); 36 } 37 38 /// WebAssembly export that accepts a string (linear memory offset, byteCount) 39 /// and calls [`greet`]. 40 /// 41 /// Note: The input parameters were returned by [`allocate`]. This is not an 42 /// ownership transfer, so the inputs can be reused after this call. 43 #[cfg_attr(all(target_arch = "wasm32"), export_name = "greet")] 44 #[no_mangle] 45 pub unsafe extern "C" fn _greet(ptr: u32, len: u32) { 46 greet(&ptr_to_string(ptr, len)); 47 } 48 49 /// WebAssembly export that accepts a string (linear memory offset, byteCount) 50 /// and returns a pointer/size pair packed into a u64. 51 /// 52 /// Note: The return value is leaked to the caller, so it must call 53 /// [`deallocate`] when finished. 54 /// Note: This uses a u64 instead of two result values for compatibility with 55 /// WebAssembly 1.0. 56 #[cfg_attr(all(target_arch = "wasm32"), export_name = "greeting")] 57 #[no_mangle] 58 pub unsafe extern "C" fn _greeting(ptr: u32, len: u32) -> u64 { 59 let name = &ptr_to_string(ptr, len); 60 let g = greeting(name); 61 let (ptr, len) = string_to_ptr(&g); 62 // Note: This changes ownership of the pointer to the external caller. If 63 // we didn't call forget, the caller would read back a corrupt value. Since 64 // we call forget, the caller must deallocate externally to prevent leaks. 65 std::mem::forget(g); 66 return ((ptr as u64) << 32) | len as u64; 67 } 68 69 /// Returns a string from WebAssembly compatible numeric types representing 70 /// its pointer and length. 71 unsafe fn ptr_to_string(ptr: u32, len: u32) -> String { 72 let slice = slice::from_raw_parts_mut(ptr as *mut u8, len as usize); 73 let utf8 = std::str::from_utf8_unchecked_mut(slice); 74 return String::from(utf8); 75 } 76 77 /// Returns a pointer and size pair for the given string in a way compatible 78 /// with WebAssembly numeric types. 79 /// 80 /// Note: This doesn't change the ownership of the String. To intentionally 81 /// leak it, use [`std::mem::forget`] on the input after calling this. 82 unsafe fn string_to_ptr(s: &String) -> (u32, u32) { 83 return (s.as_ptr() as u32, s.len() as u32); 84 } 85 86 /// Set the global allocator to the WebAssembly optimized one. 87 #[global_allocator] 88 static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 89 90 /// WebAssembly export that allocates a pointer (linear memory offset) that can 91 /// be used for a string. 92 /// 93 /// This is an ownership transfer, which means the caller must call 94 /// [`deallocate`] when finished. 95 #[cfg_attr(all(target_arch = "wasm32"), export_name = "allocate")] 96 #[no_mangle] 97 pub extern "C" fn _allocate(size: u32) -> *mut u8 { 98 allocate(size as usize) 99 } 100 101 /// Allocates size bytes and leaks the pointer where they start. 102 fn allocate(size: usize) -> *mut u8 { 103 // Allocate the amount of bytes needed. 104 let vec: Vec<MaybeUninit<u8>> = Vec::with_capacity(size); 105 106 // into_raw leaks the memory to the caller. 107 Box::into_raw(vec.into_boxed_slice()) as *mut u8 108 } 109 110 111 /// WebAssembly export that deallocates a pointer of the given size (linear 112 /// memory offset, byteCount) allocated by [`allocate`]. 113 #[cfg_attr(all(target_arch = "wasm32"), export_name = "deallocate")] 114 #[no_mangle] 115 pub unsafe extern "C" fn _deallocate(ptr: u32, size: u32) { 116 deallocate(ptr as *mut u8, size as usize); 117 } 118 119 /// Retakes the pointer which allows its memory to be freed. 120 unsafe fn deallocate(ptr: *mut u8, size: usize) { 121 let _ = Vec::from_raw_parts(ptr, 0, size); 122 }