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  }