Files
extism/runtime
dependabot[bot] 9415aaa08a chore(deps): Update cbindgen requirement from 0.28 to 0.29 (#854)
Updates the requirements on
[cbindgen](https://github.com/mozilla/cbindgen) to permit the latest
version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/mozilla/cbindgen/releases">cbindgen's
releases</a>.</em></p>
<blockquote>
<h1>0.29.0</h1>
<ul>
<li>Support no-export annotation for statics and functions.</li>
<li>Fixed conditional fields of constexpr literal structs</li>
<li>Add rename rule for generated associated constant</li>
<li>Upgrade heck to 0.5</li>
<li>Add support for an optional nullable attribute</li>
<li>docs.md: Fix deprecated_with_note and deprecated_variant_with_note
being spelled as 'notes'</li>
<li>Fix generic with &quot;void&quot; default</li>
<li>Fixed error generation of structures using the keyword as inside
arrays</li>
<li>Added test for unsafe(no_mangle) attribute</li>
<li>Fixed handling of trait methods containing the unsafe attribute</li>
<li>Rename -Zparse-only</li>
</ul>
<h1>0.28.0</h1>
<ul>
<li>Parse unsafe attributes in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1020">mozilla/cbindgen#1020</a></li>
<li>Fix local override of enum prefix-with-name by jsgf in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1006">mozilla/cbindgen#1006</a></li>
<li>Add rename-all=prefix in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1021">mozilla/cbindgen#1021</a></li>
<li>ir: add support for UnsafeCell and SyncUnsafeCell by alekitto in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1003">mozilla/cbindgen#1003</a></li>
<li>Implement mangling for arrays in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1022">mozilla/cbindgen#1022</a></li>
<li>Fix: Ignore <code>CARGO_BUILD_TARGET</code> in tests by bryango in
<a
href="https://redirect.github.com/mozilla/cbindgen/pull/1010">mozilla/cbindgen#1010</a></li>
<li>Newline for each field for constexpr field constants by youknowone
in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/988">mozilla/cbindgen#988</a></li>
<li>Fix clippy warnings by youknowone in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1026">mozilla/cbindgen#1026</a></li>
<li>Add aarch64/arm64 to CI by NickeZ in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1036">mozilla/cbindgen#1036</a></li>
<li>Add <code>unstable_ir</code> feature flag that makes the ir pub by
heesooy in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1011">mozilla/cbindgen#1011</a></li>
<li>Support generated a symbols file by TheElectronWill in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/916">mozilla/cbindgen#916</a></li>
</ul>
<h1>0.27.0</h1>
<ul>
<li>Revert: The <code>Config</code> struct now has a private
member.</li>
<li>Allow users to specify a crate version for bindings generation (<a
href="https://redirect.github.com/mozilla/cbindgen/issues/901">#901</a>).</li>
<li>Update MSRV to 1.74 (<a
href="https://redirect.github.com/mozilla/cbindgen/issues/912">#912</a>,
<a
href="https://redirect.github.com/mozilla/cbindgen/issues/987">#987</a>).</li>
<li>Support #[deprecated] on enum variants (<a
href="https://redirect.github.com/mozilla/cbindgen/issues/933">#933</a>).</li>
<li>Support integrating the package_version information in a header file
comment (<a
href="https://redirect.github.com/mozilla/cbindgen/issues/939">#939</a>).</li>
<li>Add a language backend (<a
href="https://redirect.github.com/mozilla/cbindgen/issues/942">#942</a>).</li>
<li>Support generics with defaulted args (<a
href="https://redirect.github.com/mozilla/cbindgen/issues/959">#959</a>).</li>
<li>Add <code>VaList</code> compatibility (<a
href="https://redirect.github.com/mozilla/cbindgen/issues/970">#970</a>).</li>
</ul>
<h1>0.26.0</h1>
<ul>
<li>Fix swapping of <code>&gt;&gt;=</code> and <code>&lt;&lt;=</code> in
constants.</li>
<li>Add support for #[deprecated] (<a
href="https://redirect.github.com/mozilla/cbindgen/issues/860">#860</a>).</li>
<li>Built-in support for bitflags 2.0.</li>
<li>Support for &quot;C-unwind&quot; ABI.</li>
<li>Generate bindings for non-public extern items if they are
#[no_mangle].</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/mozilla/cbindgen/blob/master/CHANGES">cbindgen's
changelog</a>.</em></p>
<blockquote>
<h1>0.29.0</h1>
<pre><code>  * Support no-export annotation for statics and functions.
  * Fixed conditional fields of constexpr literal structs
  * Add rename rule for generated associated constant
  * Upgrade heck to 0.5
  * Add support for an optional nullable attribute
* docs.md: Fix deprecated_with_note and deprecated_variant_with_note
being spelled as 'notes'
  * Fix generic with &quot;void&quot; default
* Fixed error generation of structures using the keyword as inside
arrays
  * Added test for unsafe(no_mangle) attribute
  * Fixed handling of trait methods containing the unsafe attribute
  * Rename -Zparse-only
</code></pre>
<h1>0.28.0</h1>
<pre><code> * Parse unsafe attributes in
https://github.com/mozilla/cbindgen/pull/1020
* Fix local override of enum prefix-with-name by jsgf in
https://github.com/mozilla/cbindgen/pull/1006
* Add rename-all=prefix in https://github.com/mozilla/cbindgen/pull/1021
* ir: add support for UnsafeCell and SyncUnsafeCell by alekitto in
https://github.com/mozilla/cbindgen/pull/1003
* Implement mangling for arrays in
https://github.com/mozilla/cbindgen/pull/1022
* Fix: Ignore `CARGO_BUILD_TARGET` in tests by bryango in
https://github.com/mozilla/cbindgen/pull/1010
* Newline for each field for constexpr field constants by youknowone in
https://github.com/mozilla/cbindgen/pull/988
* Fix clippy warnings by youknowone in
https://github.com/mozilla/cbindgen/pull/1026
* Add aarch64/arm64 to CI by NickeZ in
https://github.com/mozilla/cbindgen/pull/1036
* Add `unstable_ir` feature flag that makes the ir pub by heesooy in
https://github.com/mozilla/cbindgen/pull/1011
* Support generated a symbols file by TheElectronWill in
https://github.com/mozilla/cbindgen/pull/916
</code></pre>
<h1>0.27.0</h1>
<pre><code>  * Revert: The `Config` struct now has a private member.
* Allow users to specify a crate version for bindings generation
([#901](https://github.com/mozilla/cbindgen/issues/901)).
* Update MSRV to 1.74
([#912](https://github.com/mozilla/cbindgen/issues/912),
[#987](https://github.com/mozilla/cbindgen/issues/987)).
* Support #[deprecated] on enum variants
([#933](https://github.com/mozilla/cbindgen/issues/933)).
* Support integrating the package_version information in a header file
comment ([#939](https://github.com/mozilla/cbindgen/issues/939)).
* Add a language backend
([#942](https://github.com/mozilla/cbindgen/issues/942)).
* Support generics with defaulted args
([#959](https://github.com/mozilla/cbindgen/issues/959)).
* Add `VaList` compatibility
([#970](https://github.com/mozilla/cbindgen/issues/970)).
</code></pre>
<h1>0.26.0</h1>
<pre><code>  * Fix swapping of `&gt;&gt;=` and `&lt;&lt;=` in constants.
* Add support for #[deprecated]
([#860](https://github.com/mozilla/cbindgen/issues/860)).
  * Built-in support for bitflags 2.0.
  * Support for &quot;C-unwind&quot; ABI.
* Generate bindings for non-public extern items if they are
#[no_mangle].
</code></pre>
<h2>0.25.0</h2>
<pre><code>  * Re-release of yanked 0.24.6 as a major release
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="802154245e"><code>8021542</code></a>
Release 0.29.0</li>
<li><a
href="f3a0ecd2a9"><code>f3a0ecd</code></a>
Support no-export annotation for statics and functions.</li>
<li><a
href="14fa2d0669"><code>14fa2d0</code></a>
conditional fields of constexpr literal structs</li>
<li><a
href="021f3f3a42"><code>021f3f3</code></a>
Add LiteralStructField</li>
<li><a
href="4b2396dabf"><code>4b2396d</code></a>
Github action: Add aarch64 to deploy</li>
<li><a
href="2320ac4296"><code>2320ac4</code></a>
Add rename rule for generated associated constant</li>
<li><a
href="5ac9dc046b"><code>5ac9dc0</code></a>
Upgrade heck to 0.5</li>
<li><a
href="9f9da30c60"><code>9f9da30</code></a>
Add support for an optional nullable attribute</li>
<li><a
href="36b9f0df42"><code>36b9f0d</code></a>
docs.md: Fix deprecated_with_note and deprecated_variant_with_note being
spel...</li>
<li><a
href="0328601dc1"><code>0328601</code></a>
Fix generic with &quot;void&quot; default</li>
<li>Additional commits viewable in <a
href="https://github.com/mozilla/cbindgen/compare/0.28.0...0.29.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-27 12:36:33 -07:00
..
2024-11-14 12:32:22 -08:00
2024-11-14 12:32:22 -08:00

Extism runtime and rust-sdk

This repo contains the code for the Extism runtime and rust-sdk. It can be embedded in any Rust application to call Extism plug-ins.

Note

: If you're unsure what Extism is or what an SDK is see our homepage: https://extism.org.

Installation

Cargo

To use the extism crate, you can add it to your Cargo file:

[dependencies]
extism = "1.4.1"

Environment variables

There are a few environment variables that can be used for debugging purposes:

  • EXTISM_ENABLE_WASI_OUTPUT=1: show WASI stdout/stderr
  • EXTISM_MEMDUMP=extism.mem: dump Extism linear memory to a file
  • EXTISM_COREDUMP=extism.core: write coredump to a file when a WebAssembly function traps
  • EXTISM_DEBUG=1: generate debug information
  • EXTISM_PROFILE=perf|jitdump|vtune: enable Wasmtime profiling
  • EXTISM_CACHE_CONFIG=path/to/config.toml: enable Wasmtime cache, see the docs for details about configuration. Setting this to an empty string will disable caching.

Note

: The debug and coredump info will only be written if the plug-in has an error.

Getting Started

This guide should walk you through some of the concepts in Extism and the extism crate.

Creating A Plug-in

The primary concept in Extism is the plug-in. You can think of a plug-in as a code module stored in a .wasm file.

Since you may not have an Extism plug-in on hand to test, let's load a demo plug-in from the web:

use extism::*;

fn main() {
  let url = Wasm::url(
    "https://github.com/extism/plugins/releases/latest/download/count_vowels.wasm"
  );
  let manifest = Manifest::new([url]);
  let mut plugin = Plugin::new(&manifest, [], true).unwrap();
  let res = plugin.call::<&str, &str>("count_vowels", "Hello, world!").unwrap();
  println!("{}", res);
}

Note

: See the Manifest docs as it has a rich schema and a lot of options.

Calling A Plug-in's Exports

This plug-in was written in Rust and it does one thing, it counts vowels in a string. As such, it exposes one "export" function: count_vowels. We can call exports using Extism::Plugin::call:

let res = plugin.call::<&str, &str>("count_vowels", "Hello, world!").unwrap();
println!("{}", res);
# => {"count": 3, "total": 3, "vowels": "aeiouAEIOU"}

All exports have a simple interface of bytes-in and bytes-out. This plug-in happens to take a string and return a JSON encoded string with a report of results.

The call function uses extism-convert to determine which input/output types can be used. If we wanted to use a concrete type for the count_vowels result, we could defined a struct:

#[derive(Debug, serde::Deserialize)]
struct VowelCount {
  count: usize,
  total: usize,
  vowels: String,
}

Then we can use Json to get the JSON results decoded into VowelCount:

let Json(res) = plugin.call::<&str, Json<VowelCount>>("count_vowels", "Hello, world!").unwrap();
println!("{:?}", res);
# => VowelCount {count: 3, total: 3, vowels: "aeiouAEIOU"}

Plug-in State

Plug-ins may be stateful or stateless. Plug-ins can maintain state between calls by the use of variables. Our count vowels plug-in remembers the total number of vowels it's ever counted in the "total" key in the result. You can see this by making subsequent calls to the export:

let res = plugin.call::<&str, &str>("count_vowels", "Hello, world!").unwrap();
println!("{}", res);
# => {"count": 3, "total": 6, "vowels": "aeiouAEIOU"}

let res = plugin.call::<&str, &str>("count_vowels", "Hello, world!").unwrap();
println!("{}", res);
# => {"count": 3, "total": 9, "vowels": "aeiouAEIOU"}

These variables will persist until this plug-in is freed or you initialize a new one.

Configuration

Plug-ins may optionally take a configuration object. This is a static way to configure the plug-in. Our count-vowels plugin takes an optional configuration to change out which characters are considered vowels. Example:

let manifest = Manifest::new([url]);
let mut plugin = Plugin::new(&manifest, [], true);
let res = plugin.call::<&str, &str>("count_vowels", "Yellow, world!").unwrap();
println!("{}", res);
# => {"count": 3, "total": 3, "vowels": "aeiouAEIOU"}
let mut plugin = Plugin::new(&manifest, [], true).with_config_key("vowels", "aeiouyAEIOUY");
let res = plugin.call::<&str, &str>("count_vowels", "Yellow, world!").unwrap();
println!("{}", res);
# => {"count": 4, "total": 4, "vowels": "aeiouyAEIOUY"}

Host Functions

Let's extend our count-vowels example a little bit: Instead of storing the total in an ephemeral plug-in var, let's store it in a persistent key-value store!

Wasm can't use our KV store on it's own. This is where Host Functions come in.

Host functions allow us to grant new capabilities to our plug-ins from our application. They are simply some Rust functions you write which can be passed down and invoked from any language inside the plug-in.

Let's load the manifest like usual but load up this count_vowels_kvstore plug-in:

let url = Wasm::url(
  "https://github.com/extism/plugins/releases/latest/download/count_vowels_kvstore.wasm"
);
let manifest = Manifest::new([url]);

Note

: The source code for this is here and is written in rust, but it could be written in any of our PDK languages.

Unlike our previous plug-in, this plug-in expects you to provide host functions that satisfy our its import interface for a KV store.

We want to expose two functions to our plugin, kv_write(key: String, value: Bytes) which writes a bytes value to a key and kv_read(key: String) -> Bytes which reads the bytes at the given key.

use extism::*;

// pretend this is redis or something :)
type KVStore = std::collections::BTreeMap<String, Vec<u8>>;

// When a first argument separated with a semicolon is provided to `host_fn` it is used as the
// variable name and type for the `UserData` parameter
host_fn!(kv_read(user_data: KVStore; key: String) -> u32 {
    let kv = user_data.get()?;
    let kv = kv.lock().unwrap();
    let value = kv
        .get(&key)
        .map(|x| u32::from_le_bytes(x.clone().try_into().unwrap()))
        .unwrap_or_else(|| 0u32);
    Ok(value)
});

host_fn!(kv_write(user_data: KVStore; key: String, value: u32) {
    let kv = user_data.get()?;
    let mut kv = kv.lock().unwrap();
    kv.insert(key, value.to_le_bytes().to_vec());
    Ok(())
});

fn main() {
    let kv_store = UserData::new(KVStore::default());

    let url = Wasm::url(
        "https://github.com/extism/plugins/releases/latest/download/count_vowels_kvstore.wasm",
    );
    let manifest = Manifest::new([url]);
    let mut plugin = PluginBuilder::new(manifest)
        .with_wasi(true)
        .with_function(
            "kv_read",
            [PTR],
            [PTR],
            kv_store.clone(),
            kv_read,
        )
        .with_function(
            "kv_write",
            [PTR, PTR],
            [],
            kv_store.clone(),
            kv_write,
        )
        .build()
        .unwrap();

    for _ in 0..5 {
        let res = plugin
            .call::<&str, &str>("count_vowels", "Hello, world!")
            .unwrap();
        println!("{}", res);
    }
}

Note

: In order to write host functions you should get familiar with the methods on the CurrentPlugin and UserData types.

Now we can invoke the event:

let res = plugin.call::<&str, &str>("count_vowels", "Hello, world!").unwrap();
println!("{}", res);
# => Read from key=count-vowels"
# => Writing value=3 from key=count-vowels"
# => {"count": 3, "total": 3, "vowels": "aeiouAEIOU"}

let res = plugin.call::<&str, &str>("count_vowels", "Hello, world!").unwrap();
println!("{}", res);
# => Read from key=count-vowels"
# => Writing value=6 from key=count-vowels"
# => {"count": 3, "total": 6, "vowels": "aeiouAEIOU"}

Logging

Plug-ins can't directly print anything to the console. They can however use Extism's built-in logging functionality, for example the log! macro in the rust-pdk or the logInfo function in the haskell-pdk.

Inside your host application, the rust-sdk emits these as tracing events. The simplest way to make the logged messages visible is by adding the tracing_subscriber dependency to your crate and then initializing a tracing subscriber at the top of your main function:

tracing_subscriber::fmt::init();