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, &params)?;
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, &params)?;
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}