Canpack
Canpack is a code generation tool designed to simplify communication across canisters written in different languages. It currently supports calling a Rust crate from Motoko code. Canpack generates a separate canister for the host language, then combines the other language's code fragments that are defined across different libraries.
Canpack supports the Mops package manager.
Canpack is still in early development. Breaking changes may be introduced at any time.
Installation
- Prerequisites
Then, install the Canpack CLI using npm
:
npm install -g canpack
Using Canpack
In a project directory that contains a dfx.json
and mops.toml
file, you can use Canpack by first creating a new file called canpack.json
with the following content:
{
"canisters": {
"motoko_rust": {
"type": "rust",
"parts": [{
"package": "canpack-example-hello",
"version": "^0.1"
}]
}
}
}
Then, generate the required files using the command:
canpack
In the project's dfx.json
file, configure the "dependencies"
for your project's Motoko canister:
{
"canisters": {
"my_project_backend": {
"dependencies": ["motoko_rust"],
"main": "src/my_project_backend/main.mo",
"type": "motoko"
}
},
}
Then, to write a Motoko canister that imports Rust crates, import Rust
from the motoko_rust
canister:
import Rust "canister:motoko_rust";
actor {
public composite query func hello(name: Text) : async Text {
await Rust.canpack_example_hello(name)
}
}
Motoko canisters can import any Rust crate that is compatible with Canpack. Canpack supports any IC Wasm-compatible crate.
Adding Canpack support to a crate
To add Canpack support to a Rust crate, export a Rust function with canpack::export!
:
canpack::export! {
pub fn canpack_example_hello(name: String) -> String {
format!("Hello, {name}!")
}
}
canpack::export!
requires that you add canpack
as a dependency in your Cargo.toml
file.
Reference local data
You can also reference local data, such as methods and constants:
const WELCOME: &str = "Welcome";
fn hello(salutation: &str, name: String) -> String {
format!("{salutation}, {name}!")
}
canpack::export! {
pub fn canpack_example_hello(name: String) -> String {
hello(WELCOME, name)
}
}
Candid methods
To configure an automatically generated Candid method for a function, use the #[canpack]
attribute,
canpack::export! {
#[canpack(composite_query, rename = "canpack_example_hello")]
pub fn hello(name: String) -> String {
format!("Hello, {name}!")
}
}
Alternatively, you can manually define a Candid method through the canpack!
macro:
pub fn hello(name: String) -> String {
format!("Hello, {name}!")
}
#[macro_export]
macro_rules! canpack {
() => {
#[ic_cdk::query]
#[candid::candid_method(query)]
fn canpack_example_hello(name: String) -> String {
$crate::hello(name)
}
};
}
Resources
Canpack is open to contributions and encourages you to report bugs, ask questions, or request features using the project's GitHub issues.