wamr_rust_sdk/lib.rs
1/*
2 * Copyright (C) 2019 Intel Corporation. All rights reserved.
3 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4 */
5
6//! # WAMR Rust SDK
7//!
8//! ## Overview
9//!
10//! WAMR Rust SDK provides Rust language bindings for WAMR. It is the wrapper
11//! of [*wasm_export.h*](../../../core/iwasm/include/wasm_export.h) but with Rust style.
12//! It is more convenient to use WAMR in Rust with this crate.
13//!
14//! This crate contains API used to interact with Wasm modules. You can compile
15//! modules, instantiate modules, call their export functions, etc.
16//! Plus, as an embedded of Wasm, you can provide Wasm module functionality by
17//! creating host-defined functions.
18//!
19//! WAMR Rust SDK includes a [*wamr-sys*](../crates/wamr-sys) crate. It will search for
20//! the WAMR runtime source in the path *../..*. And then uses `rust-bindgen` durning
21//! the build process to make a .so.
22//!
23//! This crate has similar concepts to the
24//! [WebAssembly specification](https://webassembly.github.io/spec/core/).
25//!
26//! ### Core concepts
27//!
28//! - *Runtime*. It is the environment that hosts all the wasm modules. Each process has one runtime instance.
29//! - *Module*. It is the compiled .wasm or .aot. It can be loaded into runtime and instantiated into instance.
30//! - *Instance*. It is the running instance of a module. It can be used to call export functions.
31//! - *Function*. It is the exported function.
32//!
33//! ### WASI concepts
34//!
35//! - *WASIArgs*. It is used to configure the WASI environment.
36//! - *pre-open*. All files and directories in the list will be opened before the .wasm or .aot loaded.
37//! - *allowed address*. All ip addresses in the *allowed address* list will be allowed to connect with a socket.
38//! - *allowed DNS*.
39//!
40//! ### WAMR private concepts
41//!
42//! - *loading linking* instead of *instantiation linking*. *instantiation linking* is
43//! used in Wasm JS API and Wasm C API. It means that every instance has its own, maybe
44//! variant, imports. But *loading linking* means that all instances share the same *imports*.
45//!
46//! - *RuntimeArg*. Control runtime behavior.
47//! - *running mode*.
48//! - *allocator*.
49//!
50//! - *NativeFunction*.
51//!
52//! - *WasmValues*.
53//!
54//! ## Examples
55//!
56//! ### Example: to run a wasm32-wasip1 .wasm
57//!
58//! *wasm32-wasip1* is a most common target for Wasm. It means that the .wasm is compiled with
59//! `cargo build --target wasm32-wasip1` or `wasi-sdk/bin/clang --target wasm32-wasip1`.
60//!
61//! Say there is a gcd_wasm32_wasi.wasm which includes a function named *gcd*. It returns the GCD
62//! of two parameters.
63//!
64//! The rust code to call the function would be:
65//!
66//! ```
67//! use wamr_rust_sdk::{
68//! runtime::Runtime, module::Module, instance::Instance, function::Function,
69//! value::WasmValue, RuntimeError
70//! };
71//! use std::path::PathBuf;
72//!
73//! fn main() -> Result<(), RuntimeError> {
74//! let runtime = Runtime::new()?;
75//!
76//! let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
77//! d.push("resources/test");
78//! d.push("gcd_wasm32_wasi.wasm");
79//!
80//! let module = Module::from_file(&runtime, d.as_path())?;
81//!
82//! let instance = Instance::new(&runtime, &module, 1024 * 64)?;
83//!
84//! let function = Function::find_export_func(&instance, "gcd")?;
85//!
86//! let params: Vec<WasmValue> = vec![WasmValue::I32(9), WasmValue::I32(27)];
87//! let result = function.call(&instance, ¶ms)?;
88//! assert_eq!(result, vec![WasmValue::I32(9)]);
89//!
90//! Ok(())
91//! }
92//! ```
93//!
94//! ### Example: more configuration for runtime.
95//!
96//! With more configuration, runtime is capable to run .wasm with variant features, like
97//! - Wasm without WASI requirement. Usually, it means that the .wasm is compiled with `-nostdlib`
98//! or `--target wasm32-unknown-unknown`
99//! - Configure runtime.
100//! - Provides host-defined functions to meet import requirements.
101//!
102//! Say there is an add_extra_wasm32_wasi.wasm. Its exported function, `add()`,
103//! requires an imported function, `extra()`, during the execution. The `add()`
104//! adds two parameters and the result of `extra()` . It is like `a + b + extra()`.
105//!
106//! The rust code to call the *add* function is like this:
107//!
108//! ```
109//! use wamr_rust_sdk::{
110//! runtime::Runtime, module::Module, instance::Instance, function::Function,
111//! value::WasmValue, RuntimeError
112//! };
113//! use std::path::PathBuf;
114//! use std::ffi::c_void;
115//!
116//! extern "C" fn extra() -> i32 {
117//! 100
118//! }
119//!
120//! fn main() -> Result<(), RuntimeError> {
121//! let runtime = Runtime::builder()
122//! .use_system_allocator()
123//! .register_host_function("extra", extra as *mut c_void)
124//! .build()?;
125//!
126//! let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
127//! d.push("resources/test");
128//! d.push("add_extra_wasm32_wasi.wasm");
129//! let module = Module::from_file(&runtime, d.as_path())?;
130//!
131//! let instance = Instance::new(&runtime, &module, 1024 * 64)?;
132//!
133//! let function = Function::find_export_func(&instance, "add")?;
134//!
135//! let params: Vec<WasmValue> = vec![WasmValue::I32(9), WasmValue::I32(27)];
136//! let result = function.call(&instance, ¶ms)?;
137//! assert_eq!(result, vec![WasmValue::I32(136)]);
138//!
139//! Ok(())
140//! }
141//! ```
142//!
143
144use std::error;
145use std::fmt;
146use std::io;
147pub use wamr_sys as sys;
148
149pub mod function;
150mod helper;
151pub mod host_function;
152pub mod instance;
153pub mod module;
154pub mod runtime;
155pub mod value;
156pub mod wasi_context;
157
158#[derive(Debug)]
159pub struct ExecError {
160 pub message: String,
161 pub exit_code: u32,
162}
163
164/// all kinds of exceptions raised by WAMR
165#[derive(Debug)]
166pub enum RuntimeError {
167 NotImplemented,
168 /// Runtime initialization error.
169 InitializationFailure,
170 /// file operation error. usually while loading(compilation) a .wasm
171 WasmFileFSError(std::io::Error),
172 /// A compilation error. usually means that the .wasm file is invalid
173 CompilationError(String),
174 /// instantiation failure
175 InstantiationFailure(String),
176 /// Error during execute wasm functions
177 ExecutionError(ExecError),
178 /// usually returns by `find_export_func()`
179 FunctionNotFound,
180}
181
182impl fmt::Display for RuntimeError {
183 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184 match self {
185 RuntimeError::NotImplemented => write!(f, "Not implemented"),
186 RuntimeError::InitializationFailure => write!(f, "Runtime initialization failure"),
187 RuntimeError::WasmFileFSError(e) => write!(f, "Wasm file operation error: {}", e),
188 RuntimeError::CompilationError(e) => write!(f, "Wasm compilation error: {}", e),
189 RuntimeError::InstantiationFailure(e) => write!(f, "Wasm instantiation failure: {}", e),
190 RuntimeError::ExecutionError(info) => write!(
191 f,
192 "Wasm execution error: {} and {}",
193 info.message, info.exit_code
194 ),
195 RuntimeError::FunctionNotFound => write!(f, "Function not found"),
196 }
197 }
198}
199
200impl error::Error for RuntimeError {
201 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
202 match self {
203 RuntimeError::WasmFileFSError(e) => Some(e),
204 _ => None,
205 }
206 }
207}
208
209impl From<io::Error> for RuntimeError {
210 fn from(e: io::Error) -> Self {
211 RuntimeError::WasmFileFSError(e)
212 }
213}