| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // Copied from: |
| // https://github.com/tetratelabs/wazero/blob/v1.0.0-pre.3/examples/allocation/rust/testdata/greet.rs |
| extern crate alloc; |
| extern crate core; |
| extern crate wee_alloc; |
| |
| use alloc::vec::Vec; |
| use std::mem::MaybeUninit; |
| use std::slice; |
| |
| /// Prints a greeting to the console using [`log`]. |
| fn greet(name: &String) { |
| log(&["wasm >> ", &greeting(name)].concat()); |
| } |
| |
| /// Gets a greeting for the name. |
| fn greeting(name: &String) -> String { |
| return ["Hello, ", &name, "!"].concat(); |
| } |
| |
| /// Logs a message to the console using [`_log`]. |
| fn log(message: &String) { |
| unsafe { |
| let (ptr, len) = string_to_ptr(message); |
| _log(ptr, len); |
| } |
| } |
| |
| #[link(wasm_import_module = "env")] |
| extern "C" { |
| /// WebAssembly import which prints a string (linear memory offset, |
| /// byteCount) to the console. |
| /// |
| /// Note: This is not an ownership transfer: Rust still owns the pointer |
| /// and ensures it isn't deallocated during this call. |
| #[link_name = "log"] |
| fn _log(ptr: u32, size: u32); |
| } |
| |
| /// WebAssembly export that accepts a string (linear memory offset, byteCount) |
| /// and calls [`greet`]. |
| /// |
| /// Note: The input parameters were returned by [`allocate`]. This is not an |
| /// ownership transfer, so the inputs can be reused after this call. |
| #[cfg_attr(all(target_arch = "wasm32"), export_name = "greet")] |
| #[no_mangle] |
| pub unsafe extern "C" fn _greet(ptr: u32, len: u32) { |
| greet(&ptr_to_string(ptr, len)); |
| } |
| |
| /// WebAssembly export that accepts a string (linear memory offset, byteCount) |
| /// and returns a pointer/size pair packed into a u64. |
| /// |
| /// Note: The return value is leaked to the caller, so it must call |
| /// [`deallocate`] when finished. |
| /// Note: This uses a u64 instead of two result values for compatibility with |
| /// WebAssembly 1.0. |
| #[cfg_attr(all(target_arch = "wasm32"), export_name = "greeting")] |
| #[no_mangle] |
| pub unsafe extern "C" fn _greeting(ptr: u32, len: u32) -> u64 { |
| let name = &ptr_to_string(ptr, len); |
| let g = greeting(name); |
| let (ptr, len) = string_to_ptr(&g); |
| // Note: This changes ownership of the pointer to the external caller. If |
| // we didn't call forget, the caller would read back a corrupt value. Since |
| // we call forget, the caller must deallocate externally to prevent leaks. |
| std::mem::forget(g); |
| return ((ptr as u64) << 32) | len as u64; |
| } |
| |
| /// Returns a string from WebAssembly compatible numeric types representing |
| /// its pointer and length. |
| unsafe fn ptr_to_string(ptr: u32, len: u32) -> String { |
| let slice = slice::from_raw_parts_mut(ptr as *mut u8, len as usize); |
| let utf8 = std::str::from_utf8_unchecked_mut(slice); |
| return String::from(utf8); |
| } |
| |
| /// Returns a pointer and size pair for the given string in a way compatible |
| /// with WebAssembly numeric types. |
| /// |
| /// Note: This doesn't change the ownership of the String. To intentionally |
| /// leak it, use [`std::mem::forget`] on the input after calling this. |
| unsafe fn string_to_ptr(s: &String) -> (u32, u32) { |
| return (s.as_ptr() as u32, s.len() as u32); |
| } |
| |
| /// Set the global allocator to the WebAssembly optimized one. |
| #[global_allocator] |
| static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; |
| |
| /// WebAssembly export that allocates a pointer (linear memory offset) that can |
| /// be used for a string. |
| /// |
| /// This is an ownership transfer, which means the caller must call |
| /// [`deallocate`] when finished. |
| #[cfg_attr(all(target_arch = "wasm32"), export_name = "allocate")] |
| #[no_mangle] |
| pub extern "C" fn _allocate(size: u32) -> *mut u8 { |
| allocate(size as usize) |
| } |
| |
| /// Allocates size bytes and leaks the pointer where they start. |
| fn allocate(size: usize) -> *mut u8 { |
| // Allocate the amount of bytes needed. |
| let vec: Vec<MaybeUninit<u8>> = Vec::with_capacity(size); |
| |
| // into_raw leaks the memory to the caller. |
| Box::into_raw(vec.into_boxed_slice()) as *mut u8 |
| } |
| |
| |
| /// WebAssembly export that deallocates a pointer of the given size (linear |
| /// memory offset, byteCount) allocated by [`allocate`]. |
| #[cfg_attr(all(target_arch = "wasm32"), export_name = "deallocate")] |
| #[no_mangle] |
| pub unsafe extern "C" fn _deallocate(ptr: u32, size: u32) { |
| deallocate(ptr as *mut u8, size as usize); |
| } |
| |
| /// Retakes the pointer which allows its memory to be freed. |
| unsafe fn deallocate(ptr: *mut u8, size: usize) { |
| let _ = Vec::from_raw_parts(ptr, 0, size); |
| } |