Compare commits

...

182 Commits

Author SHA1 Message Date
zach
4a532aa58c cleanup(kernel): undo some kernel changes 2025-06-27 13:26:16 -07:00
zach
3300fed506 chore: fmt 2025-06-26 13:35:48 -07:00
zach
b026d30865 chore: clippy 2025-06-26 13:34:04 -07:00
zach
e8d0397754 test(kernel): add block re-use quickcheck test 2025-06-26 13:26:50 -07:00
zach
39685a9038 cleanup(kernel): improve re-use of freed blocks 2025-06-25 10:32:29 -07:00
Nutomic
d1ba15484e Remove key param for PluginPool (#859)
As mentioned in
https://github.com/extism/extism/pull/696/files#r1993086470, the key
parameter doesnt seem very useful. You can achieve the same effect by
doing `HashMap<Key, PluginPool>` in the client code.

---------

Co-authored-by: zach <zach@dylibso.com>
2025-06-18 12:28:39 -07:00
nu-wa
dedd81d90f docs: add more information about wasmtime caching (#863)
Hello,

I encountered an error when trying to enable caching in my project, I
could not compile any Plugins due to a bad configuration file used by
the wasmtime crate (`failed to parse config file`). I managed to find
understand the error after seeing [some changes made by
wasmtime](https://github.com/bytecodealliance/wasmtime/pull/10859) and
its documentation. I was simply missing the `enabled` key from the
configuration, that has been removed from `wasmtime` (and its [cache
sister
crate](https://github.com/bytecodealliance/wasmtime/tree/main/crates/cache)).

So I added more information in the README regarding this specific issue,
and some extra behaviour that I noticed would happen regarding caching
configuration.

Hopefully this is helpful!
2025-06-18 11:09:23 -07:00
zach
2732ca198d feat: add Pool type for pooling plugin instances (#696) 2025-06-06 10:14:22 -07:00
Muhammad Azeez
30b4a7d2d3 fix: use gh release download instead of downloading from github action artifacts in dotnet workflow (#857)
It seems like at some point we changed the `release.yml` workflow to
create multiple artifacts instead of one `release-artifacts` tarball. I
changed the .NET Nuget workflow to be more like Python
2025-05-29 22:09:52 +03:00
zach
b6e5684461 v1.11.0 2025-05-27 15:37:19 -07:00
zach
36e05e8668 chore: add ToBytes/FromBytes implementations for bool (#855)
Fixes https://github.com/extism/extism/issues/838
2025-05-27 15:35:22 -07:00
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
dependabot[bot]
168459be0f chore(deps): Update criterion requirement from 0.5.1 to 0.6.0 (#852)
Updates the requirements on
[criterion](https://github.com/bheisler/criterion.rs) to permit the
latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/bheisler/criterion.rs/blob/master/CHANGELOG.md">criterion's
changelog</a>.</em></p>
<blockquote>
<h2>[0.6.0] - 2025-05-17</h2>
<h3>Changed</h3>
<ul>
<li>MSRV bumped to 1.80</li>
<li>The <code>real_blackbox</code> feature no longer has any impact.
Criterion always uses <code>std::hint::black_box()</code> now.
Users of <code>criterion::black_box()</code> should switch to
<code>std::hint::black_box()</code>.</li>
<li><code>clap</code> dependency unpinned.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>gnuplot version is now correctly detected when using certain Windows
binaries/configurations that used to fail</li>
</ul>
<h3>Added</h3>
<ul>
<li>Async benchmarking with Tokio may be done via a
<code>tokio::runtime::Handle</code>, not only a
<code>tokio::runtime::Runtime</code></li>
</ul>
<h2>[0.5.1] - 2023-05-26</h2>
<h3>Fixed</h3>
<ul>
<li>Quick mode (--quick) no longer crashes with measured times over 5
seconds when --noplot is not active</li>
</ul>
<h2>[0.5.0] - 2023-05-23</h2>
<h3>Changed</h3>
<ul>
<li>Replaced lazy_static dependency with once_cell</li>
<li>Improved documentation of the <code>html_reports</code> feature</li>
<li>Replaced atty dependency with is-terminal</li>
<li>MSRV bumped to 1.64</li>
<li>Upgraded clap dependency to v4</li>
<li>Upgraded tempfile dependency to v3.5.0</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Quick mode (<code>--quick</code>) no longer outputs 1ms for measured
times over 5 seconds</li>
<li>Documentation updates</li>
</ul>
<h2>[0.4.0] - 2022-09-10</h2>
<h3>Removed</h3>
<ul>
<li>The <code>Criterion::can_plot</code> function has been removed.</li>
<li>The <code>Criterion::bench_function_over_inputs</code> function has
been removed.</li>
<li>The <code>Criterion::bench_functions</code> function has been
removed.</li>
<li>The <code>Criterion::bench</code> function has been removed.</li>
</ul>
<h3>Changed</h3>
<ul>
<li>HTML report hidden behind non-default feature flag:
'html_reports'</li>
<li>Standalone support (ie without cargo-criterion) feature flag:
'cargo_bench_support'</li>
<li>MSRV bumped to 1.57</li>
<li><code>rayon</code> and <code>plotters</code> are optional (and
default) dependencies.</li>
<li>Status messages ('warming up', 'analyzing', etc) are printed to
stderr, benchmark results are printed to stdout.</li>
<li>Accept subsecond durations for <code>--warm-up-time</code>,
<code>--measurement-time</code> and <code>--profile-time</code>.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="43bf90a64b"><code>43bf90a</code></a>
release version 0.6.0 (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/860">#860</a>)</li>
<li><a
href="92696e45c5"><code>92696e4</code></a>
deps: unpin clap (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/858">#858</a>)</li>
<li><a
href="5756a5d526"><code>5756a5d</code></a>
chore: bump MSRV to 1.80 (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/859">#859</a>)</li>
<li><a
href="9d887c0145"><code>9d887c0</code></a>
Fixed typo in faq.md (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/852">#852</a>)</li>
<li><a
href="59b791a587"><code>59b791a</code></a>
ci: test against MSRV and 1.87 (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/857">#857</a>)</li>
<li><a
href="ace1cc93ef"><code>ace1cc9</code></a>
Fix warnings from clippy (rust 1.87.0) (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/856">#856</a>)</li>
<li><a
href="7afab6ef7c"><code>7afab6e</code></a>
Commit Cargo.lock to make CI and local debugging more stable (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/855">#855</a>)</li>
<li><a
href="260e2f1c78"><code>260e2f1</code></a>
Update Cargo features' comments (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/825">#825</a>)</li>
<li><a
href="58130ff859"><code>58130ff</code></a>
Update to async-std v1.13 (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/812">#812</a>)</li>
<li><a
href="d2e705b855"><code>d2e705b</code></a>
Add rust-version 1.70 (<a
href="https://redirect.github.com/bheisler/criterion.rs/issues/813">#813</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/bheisler/criterion.rs/compare/0.5.1...0.6.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>
Co-authored-by: zach <zach@dylibso.com>
2025-05-19 10:10:58 -07:00
AlessandroRuggiero
1ea498b5d9 fix: better suggestion when encoding is not implemented (#843)
Here is a code snippet that demonstrates the issue:
```rust
use extism_pdk::{encoding, plugin_fn, FnResult, FromBytes, Json, ToBytes};
use serde::{Serialize, Deserialize};

#[derive(Deserialize,FromBytes)]
pub struct Input {
    value:String
}

#[derive(Serialize, ToBytes)]
pub struct Output {
    value: f64,
}

#[plugin_fn]
pub fn convert(in_value: Input) -> FnResult<Output> {
    Ok(Output { value: in_value.value.parse().expect("Conversion failed") })
}
```

Because the structs don't derive `encoding` the rust-analyzer gives this
suggestion:
```
encoding needs to be specified

  = try: `#[encoding(ToJson)]`
```

I don't think this suggestion is correct because i could not find
`ToJson` anywhere. Adding `#[encoding(Json)]` solves the issue (as
described in the docs).
The final code would look as follows:
```rust
use extism_pdk::{encoding, plugin_fn, FnResult, FromBytes, Json, ToBytes};
use serde::{Serialize, Deserialize};

#[derive(Deserialize,FromBytes)]
#[encoding(Json)]
pub struct Input {
    value:String
}

#[derive(Serialize, ToBytes)]
#[encoding(Json)]
pub struct Output {
    value: f64,
}

#[plugin_fn]
pub fn convert(in_value: Input) -> FnResult<Output> {
    Ok(Output { value: in_value.value.parse().expect("Conversion failed") })
}
```

And compiles perfectly.

I think the suggestion given by the rust-analyzer is incorrect so i am
proposing a fix for this.

Since I'm new to the project, any feedback is appreciated.
Thanks!
_Alessandro Ruggiero_
2025-03-31 08:15:23 -07:00
Pascal Sommer
f8e16dc875 doc: explain how to see plug-in logs (#839)
I know that there is already a logging example in
`runtime/examples/log_callback.rs` but I think that's not where people
go to look to figure out how the logging functionality works. At least
for me that wasn't the case :)
2025-03-21 16:56:53 -07:00
Chris Dickinson
2524707334 fix: throw error on reentrant plugin call (#836)
Previously, code that called a plugin that called a host function that
called back into the plugin would hang in an attempt to attain the lock.
Switch to `try_lock` so we can surface the error.
2025-02-26 11:37:10 -08:00
zach
de65e22f68 Remove python from dependabot.yml (#835) 2025-02-20 11:07:52 -08:00
zach
59acffa8ac chore: include wasmtime 30 in supported bounds (#834)
Also updates dependabot config to bundle wasmtime updates so this can be
done automatically in the future.
2025-02-20 10:54:42 -08:00
zach
1f46f9842d v1.10.0 2025-02-10 10:44:48 -08:00
zach
b249f09b90 fix(ci): remove path parameter from download-artifact action in release workflow (#831) 2025-02-10 10:28:23 -08:00
zach
4e638e14b1 chore: update wasmtime bounds to include more versions (#828)
Upgrades from wasmtime 26 to wasmtime 27-29, allowing us to support more
versions (including the possibility of supporting future releases
without changes)
2025-02-06 17:03:58 -08:00
zach
d7956ff08c fix(ci): use new download-artifact api (#827) 2025-02-04 13:49:19 -08:00
dependabot[bot]
87c3384f1e chore(deps): Update ureq requirement from 2.5 to 3.0 (#825)
Closes #824 

Updates the requirements on [ureq](https://github.com/algesten/ureq) to
permit the latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/algesten/ureq/blob/main/CHANGELOG.md">ureq's
changelog</a>.</em></p>
<blockquote>
<h1>3.0.3</h1>
<ul>
<li>Use the same data in CONNECT and Host header for proxied requests
(<a
href="https://redirect.github.com/algesten/ureq/issues/967">#967</a>)</li>
<li>Set default scheme in proxy uri (<a
href="https://redirect.github.com/algesten/ureq/issues/966">#966</a>)</li>
<li>Redact URI and Location header on debug level (<a
href="https://redirect.github.com/algesten/ureq/issues/964">#964</a>)</li>
<li>Downgrade all logging to debug and below (<a
href="https://redirect.github.com/algesten/ureq/issues/964">#964</a>)</li>
</ul>
<h1>3.0.2</h1>
<ul>
<li>Remove dependency on once_cell (<a
href="https://redirect.github.com/algesten/ureq/issues/959">#959</a>)</li>
<li>Fix bug parsing partial redirects (<a
href="https://redirect.github.com/algesten/ureq/issues/958">#958</a>)</li>
<li>Expose typestate variables (<a
href="https://redirect.github.com/algesten/ureq/issues/956">#956</a>)</li>
</ul>
<h1>3.0.1</h1>
<ul>
<li>Fix excessive stack sizes (<a
href="https://redirect.github.com/algesten/ureq/issues/950">#950</a>)</li>
<li>Do not enable <strong>json</strong> by default (breaking, but it was
a mistake) (<a
href="https://redirect.github.com/algesten/ureq/issues/948">#948</a>)</li>
</ul>
<h1>3.0.0</h1>
<ul>
<li>Replace RequestBuilder Deref with explicit wrappers (<a
href="https://redirect.github.com/algesten/ureq/issues/944">#944</a>)</li>
<li>Remove dependency on <code>url</code> crate (<a
href="https://redirect.github.com/algesten/ureq/issues/943">#943</a>)</li>
<li>Feature <code>Config::save_redirect_history</code> (<a
href="https://redirect.github.com/algesten/ureq/issues/939">#939</a>)</li>
</ul>
<h1>3.0.0-rc5</h1>
<ul>
<li><code>TlsConfig::unversioned_rustls_crypto_provider()</code> (<a
href="https://redirect.github.com/algesten/ureq/issues/931">#931</a>)</li>
<li>Feature <code>rustls-no-provider</code> to compile without ring (<a
href="https://redirect.github.com/algesten/ureq/issues/931">#931</a>)</li>
<li>Fix CONNECT proxy Host header (<a
href="https://redirect.github.com/algesten/ureq/issues/936">#936</a>)</li>
<li>Re-enable CONNECT proxy support (<a
href="https://redirect.github.com/algesten/ureq/issues/932">#932</a>)</li>
<li>Body::content_length (<a
href="https://redirect.github.com/algesten/ureq/issues/927">#927</a>)</li>
<li>Handle Authorization: Basic from URI (<a
href="https://redirect.github.com/algesten/ureq/issues/923">#923</a>)</li>
<li>Remove many uses of Box::new() from Connector chain (<a
href="https://redirect.github.com/algesten/ureq/issues/919">#919</a>)</li>
</ul>
<h1>3.0.0-rc4</h1>
<ul>
<li>Default to <code>TooManyRedirects</code> error (<a
href="https://redirect.github.com/algesten/ureq/issues/916">#916</a>)</li>
<li>Add <code>ConfigBuilder::max_redirects_will_error()</code> (<a
href="https://redirect.github.com/algesten/ureq/issues/916">#916</a>)</li>
<li>Add new <code>SendBody::into_reader()</code> (<a
href="https://redirect.github.com/algesten/ureq/issues/914">#914</a>)</li>
<li>Fix completely broken PEM parsing (<a
href="https://redirect.github.com/algesten/ureq/issues/912">#912</a>)</li>
<li>Improve ergonomics for <code>AutoHeaderValue</code> (<a
href="https://redirect.github.com/algesten/ureq/issues/896">#896</a>)</li>
</ul>
<h1>3.0.0-rc3</h1>
<ul>
<li>Re-export ureq_proto::ArrayVec (<a
href="https://redirect.github.com/algesten/ureq/issues/891">#891</a>)</li>
<li>Expose typestate variables, but #[doc(hidden)] (<a
href="https://redirect.github.com/algesten/ureq/issues/889">#889</a>)</li>
<li>Clarify versioning and MSRV policy (<a
href="https://redirect.github.com/algesten/ureq/issues/887">#887</a>)</li>
<li>Get last used uri via <code>ResponseExt::get_uri()</code> (<a
href="https://redirect.github.com/algesten/ureq/issues/884">#884</a>)</li>
<li>Expose more things for 3rd party Transport impls (<a
href="https://redirect.github.com/algesten/ureq/issues/886">#886</a>)</li>
<li>Make accessor fn for <code>Config</code> and <code>TlsConfig</code>
(<a
href="https://redirect.github.com/algesten/ureq/issues/886">#886</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="5cb17e8e1f"><code>5cb17e8</code></a>
Update doc</li>
<li><a
href="81127cfc38"><code>81127cf</code></a>
3.0.3</li>
<li><a
href="89d593c31c"><code>89d593c</code></a>
proxy: use the same data for CONNECT and Host header</li>
<li><a
href="e2e27ea654"><code>e2e27ea</code></a>
Set default proxy scheme in proxy uri</li>
<li><a
href="7533c1ad45"><code>7533c1a</code></a>
Update changelog</li>
<li><a
href="0d274df41b"><code>0d274df</code></a>
Use more constants for headers</li>
<li><a
href="0a4f6d7d75"><code>0a4f6d7</code></a>
Redact Location header</li>
<li><a
href="50347206a1"><code>5034720</code></a>
Downgrade info! level to debug!</li>
<li><a
href="4173dd49d7"><code>4173dd4</code></a>
ureq-proto 0.3.0</li>
<li><a
href="3d5f182fa3"><code>3d5f182</code></a>
3.0.2</li>
<li>Additional commits viewable in <a
href="https://github.com/algesten/ureq/compare/2.5.0...3.0.3">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>
Co-authored-by: zach <zach@dylibso.com>
2025-02-04 11:30:53 -08:00
dependabot[bot]
07047eaab0 chore(deps): Update rand requirement from 0.8.5 to 0.9.0 (#826)
Updates the requirements on [rand](https://github.com/rust-random/rand)
to permit the latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/rust-random/rand/blob/master/CHANGELOG.md">rand's
changelog</a>.</em></p>
<blockquote>
<h2>[0.9.0] - 2025-01-27</h2>
<h3>Security and unsafe</h3>
<ul>
<li>Policy: &quot;rand is not a crypto library&quot; (<a
href="https://redirect.github.com/rust-random/rand/issues/1514">#1514</a>)</li>
<li>Remove fork-protection from <code>ReseedingRng</code> and
<code>ThreadRng</code>. Instead, it is recommended to call
<code>ThreadRng::reseed</code> on fork. (<a
href="https://redirect.github.com/rust-random/rand/issues/1379">#1379</a>)</li>
<li>Use <code>zerocopy</code> to replace some <code>unsafe</code> code
(<a
href="https://redirect.github.com/rust-random/rand/issues/1349">#1349</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1393">#1393</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1446">#1446</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1502">#1502</a>)</li>
</ul>
<h3>Dependencies</h3>
<ul>
<li>Bump the MSRV to 1.63.0 (<a
href="https://redirect.github.com/rust-random/rand/issues/1207">#1207</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1246">#1246</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1269">#1269</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1341">#1341</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1416">#1416</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1536">#1536</a>);
note that 1.60.0 may work for dependents when using
<code>--ignore-rust-version</code></li>
<li>Update to <code>rand_core</code> v0.9.0 (<a
href="https://redirect.github.com/rust-random/rand/issues/1558">#1558</a>)</li>
</ul>
<h3>Features</h3>
<ul>
<li>Support <code>std</code> feature without <code>getrandom</code> or
<code>rand_chacha</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1354">#1354</a>)</li>
<li>Enable feature <code>small_rng</code> by default (<a
href="https://redirect.github.com/rust-random/rand/issues/1455">#1455</a>)</li>
<li>Remove implicit feature <code>rand_chacha</code>; use
<code>std_rng</code> instead. (<a
href="https://redirect.github.com/rust-random/rand/issues/1473">#1473</a>)</li>
<li>Rename feature <code>serde1</code> to <code>serde</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1477">#1477</a>)</li>
<li>Rename feature <code>getrandom</code> to <code>os_rng</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1537">#1537</a>)</li>
<li>Add feature <code>thread_rng</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1547">#1547</a>)</li>
</ul>
<h3>API changes: rand_core traits</h3>
<ul>
<li>Add fn <code>RngCore::read_adapter</code> implementing
<code>std::io::Read</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1267">#1267</a>)</li>
<li>Add trait <code>CryptoBlockRng: BlockRngCore</code>; make
<code>trait CryptoRng: RngCore</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1273">#1273</a>)</li>
<li>Add traits <code>TryRngCore</code>, <code>TryCryptoRng</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1424">#1424</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1499">#1499</a>)</li>
<li>Rename <code>fn SeedableRng::from_rng</code> -&gt;
<code>try_from_rng</code> and add infallible variant <code>fn
from_rng</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1424">#1424</a>)</li>
<li>Rename <code>fn SeedableRng::from_entropy</code> -&gt;
<code>from_os_rng</code> and add fallible variant <code>fn
try_from_os_rng</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1424">#1424</a>)</li>
<li>Add bounds <code>Clone</code> and <code>AsRef</code> to associated
type <code>SeedableRng::Seed</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1491">#1491</a>)</li>
</ul>
<h3>API changes: Rng trait and top-level fns</h3>
<ul>
<li>Rename fn <code>rand::thread_rng()</code> to
<code>rand::rng()</code> and remove from the prelude (<a
href="https://redirect.github.com/rust-random/rand/issues/1506">#1506</a>)</li>
<li>Remove fn <code>rand::random()</code> from the prelude (<a
href="https://redirect.github.com/rust-random/rand/issues/1506">#1506</a>)</li>
<li>Add top-level fns <code>random_iter</code>,
<code>random_range</code>, <code>random_bool</code>,
<code>random_ratio</code>, <code>fill</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1488">#1488</a>)</li>
<li>Re-introduce fn <code>Rng::gen_iter</code> as
<code>random_iter</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1305">#1305</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1500">#1500</a>)</li>
<li>Rename fn <code>Rng::gen</code> to <code>random</code> to avoid
conflict with the new <code>gen</code> keyword in Rust 2024 (<a
href="https://redirect.github.com/rust-random/rand/issues/1438">#1438</a>)</li>
<li>Rename fns <code>Rng::gen_range</code> to <code>random_range</code>,
<code>gen_bool</code> to <code>random_bool</code>,
<code>gen_ratio</code> to <code>random_ratio</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1505">#1505</a>)</li>
<li>Annotate panicking methods with <code>#[track_caller]</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1442">#1442</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1447">#1447</a>)</li>
</ul>
<h3>API changes: RNGs</h3>
<ul>
<li>Fix <code>&lt;SmallRng as SeedableRng&gt;::Seed</code> size to 256
bits (<a
href="https://redirect.github.com/rust-random/rand/issues/1455">#1455</a>)</li>
<li>Remove first parameter (<code>rng</code>) of
<code>ReseedingRng::new</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1533">#1533</a>)</li>
</ul>
<h3>API changes: Sequences</h3>
<ul>
<li>Split trait <code>SliceRandom</code> into
<code>IndexedRandom</code>, <code>IndexedMutRandom</code>,
<code>SliceRandom</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1382">#1382</a>)</li>
<li>Add <code>IndexedRandom::choose_multiple_array</code>,
<code>index::sample_array</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1453">#1453</a>,
<a
href="https://redirect.github.com/rust-random/rand/issues/1469">#1469</a>)</li>
</ul>
<h3>API changes: Distributions: renames</h3>
<ul>
<li>Rename module <code>rand::distributions</code> to
<code>rand::distr</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1470">#1470</a>)</li>
<li>Rename distribution <code>Standard</code> to
<code>StandardUniform</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1526">#1526</a>)</li>
<li>Move <code>distr::Slice</code> -&gt;
<code>distr::slice::Choose</code>, <code>distr::EmptySlice</code> -&gt;
<code>distr::slice::Empty</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1548">#1548</a>)</li>
<li>Rename trait <code>distr::DistString</code> -&gt;
<code>distr::SampleString</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1548">#1548</a>)</li>
<li>Rename <code>distr::DistIter</code> -&gt; <code>distr::Iter</code>,
<code>distr::DistMap</code> -&gt; <code>distr::Map</code> (<a
href="https://redirect.github.com/rust-random/rand/issues/1548">#1548</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="96f8df65ee"><code>96f8df6</code></a>
Prepare 0.9.0 release (<a
href="https://redirect.github.com/rust-random/rand/issues/1558">#1558</a>)</li>
<li><a
href="34da3214df"><code>34da321</code></a>
Enable <code>stdarch_x86_avx512</code> for cpu has <code>avx512bw</code>
(<a
href="https://redirect.github.com/rust-random/rand/issues/1551">#1551</a>)</li>
<li><a
href="b4b1eb7579"><code>b4b1eb7</code></a>
Re-org with distr::slice, distr::weighted modules (<a
href="https://redirect.github.com/rust-random/rand/issues/1548">#1548</a>)</li>
<li><a
href="16eb7de94a"><code>16eb7de</code></a>
Add the <code>thread_rng</code> feature flag (<a
href="https://redirect.github.com/rust-random/rand/issues/1547">#1547</a>)</li>
<li><a
href="afa24e49b4"><code>afa24e4</code></a>
Fix test status badges (<a
href="https://redirect.github.com/rust-random/rand/issues/1544">#1544</a>)</li>
<li><a
href="c681dfc345"><code>c681dfc</code></a>
Create FUNDING.yml</li>
<li><a
href="9f05e22afb"><code>9f05e22</code></a>
Update: getrandom v0.3.0 rc.0 (<a
href="https://redirect.github.com/rust-random/rand/issues/1541">#1541</a>)</li>
<li><a
href="88c310b189"><code>88c310b</code></a>
Fix docs.rs build options (<a
href="https://redirect.github.com/rust-random/rand/issues/1539">#1539</a>)</li>
<li><a
href="b879689a60"><code>b879689</code></a>
Adjust GH Actions (<a
href="https://redirect.github.com/rust-random/rand/issues/1538">#1538</a>)</li>
<li><a
href="3fac49fe89"><code>3fac49f</code></a>
Prepare 0.9.0-beta.0 (<a
href="https://redirect.github.com/rust-random/rand/issues/1535">#1535</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/rust-random/rand/compare/0.8.5...0.9.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>
Co-authored-by: zach <zach@dylibso.com>
2025-02-04 10:21:53 -08:00
zach
1e281e93cd cleanup: remove android release (#823)
Also switches to actions-rust-lang/setup-rust-toolchain@v1 since
actions-rs/toolchain is deprecated
2025-01-28 15:53:13 -08:00
zach
f57d987d48 ci: fix android release, attempt #2 (#818) 2025-01-21 12:08:18 -08:00
zach
9da6d43f05 ci: install android libunwind before build step (#817)
Fixes #816
2025-01-21 11:41:10 -08:00
zach
d1a248e19e cleanup: stop timer from using 100% cpu when no timeouts are set (#814)
Fixes an issue reported on discord
(https://discord.com/channels/1011124058408112148/1154513155209298041/1329622656235864156)
where the timer thread is taking up an entire CPU
2025-01-20 14:01:37 -08:00
dependabot[bot]
7b2db7588b chore(deps): Update cbindgen requirement from 0.27 to 0.28 (#815)
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.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>
</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.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
  * Update MSRV to 1.57
* Support variadic arguments (`...`)
([#805](https://github.com/mozilla/cbindgen/issues/805))
* Add --depfile option
([#820](https://github.com/mozilla/cbindgen/issues/820))
  * Breaking changes: The `Config` struct now has a private member.
</code></pre>
<h2>0.24.6 (YANKED: depfile option was breaking, see <a
href="https://redirect.github.com/mozilla/cbindgen/issues/841">#841</a>)</h2>
<pre><code>  * Update MSRV to 1.57
* Support variadic arguments (`...`)
([#805](https://github.com/mozilla/cbindgen/issues/805))
* Add --depfile option
([#820](https://github.com/mozilla/cbindgen/issues/820))
</code></pre>
<h2>0.24.5</h2>
<pre><code>  * Don't enforce tempfile version.
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bd78bbe59b"><code>bd78bbe</code></a>
Release 0.28.0</li>
<li><a
href="8ca9c4c20f"><code>8ca9c4c</code></a>
tests: Fix symbol file and tests.</li>
<li><a
href="152f91dee0"><code>152f91d</code></a>
Appease clippy.</li>
<li><a
href="70b9d7a980"><code>70b9d7a</code></a>
tests: Run rustfmt.</li>
<li><a
href="87afbf9e01"><code>87afbf9</code></a>
Add a way to generate a list of symbols for dynamic linkage, resolves <a
href="https://redirect.github.com/mozilla/cbindgen/issues/907">#907</a></li>
<li><a
href="80c50c643a"><code>80c50c6</code></a>
Add <code>unstable_ir</code> feature flag that makes the ir pub</li>
<li><a
href="e82815e99a"><code>e82815e</code></a>
Refactor arm64 build to matrix strategy</li>
<li><a
href="a5e1443a45"><code>a5e1443</code></a>
Add aarch64/arm64 to CI</li>
<li><a
href="b9b8f8878a"><code>b9b8f88</code></a>
Fix clippy warnings</li>
<li><a
href="89a9faa97c"><code>89a9faa</code></a>
newlines for constexpr</li>
<li>Additional commits viewable in <a
href="https://github.com/mozilla/cbindgen/compare/v0.27.0...0.28.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-01-20 14:01:02 -08:00
Benjamin Eckel
a367bc77a3 Add Android targets (#812)
Closes #811

Keep in mind that these targets seem to be tier 3 support and not quite
stable, but i think it's fine to open for experimenting:
https://docs.wasmtime.dev/stability-tiers.html
2025-01-14 10:23:59 -08:00
pwnintended
98800fe8a0 feat: added a function to track fuel consumption (#807)
This PR adds a function to get the fuel consumed by a plugin. This is
useful for systems that want to fairly balance compute. It's my first
time doing anything in rust so let me know if something needs
improvements!

---------

Co-authored-by: zach <zach@dylibso.com>
2024-12-16 16:04:05 -08:00
zach
7e3665ae8c fix: improve sdk error messages around imports (#806)
Closes https://github.com/extism/extism/issues/801


Updates the error from:

```
Unable to compile Extism plugin: incompatible import type for `extism:host/user::wrong_type`
```

to:

```
Unable to compile Extism plugin: types incompatible: expected type `(func (result i32))`, found type `(func (result i64))`
```
2024-12-13 11:45:24 -08:00
Muhammad Azeez
3cfde7966d Trigger NuGet package publishing when a new release is published (#805)
This makes sure the latest releases are always available on NuGet too
2024-12-05 19:44:33 +03:00
zach
5d18cc71eb chore: fix clippy (#799) 2024-12-02 16:46:48 -08:00
Miles Johnson
4f599d4b20 Change function_exists to &self (#796)
I wrap the `Plugin` instance in a `RwLock` and because `function_exists`
requires `&mut self`, I have to acquire a write lock everytime to just
check if a function exists, which causes lock contention.

This changes it to `&self` since it doesn't need to mutate.
2024-12-02 09:46:38 -08:00
Chris Dickinson
4db57de98e fix: remove unwrap() from extism_compiled_plugin_new
`extism_compiled_plugin_new` would panic on bad manifest input (there's
a test in the python sdk [1] that hits this directly.) Catch the error and
set `errmsg` appropriately instead.

Additionally: golf the function pointer casting for the various `plugin_new` calls,
with the goal of reducing the number of allocations by leaning on iterator size
hints (and reducing the scope of `unsafe{}` use.) This part can be severed: it
introduces a breaking change. Previously `NULL` values were silently accepted in
the `functions**` list; now they fail. This maintains consistency with behavior on
"consumed" `ExtismFunction` pointer.

[1]: https://github.com/extism/python-sdk/blob/main/tests/test_extism.py#L50-L53
2024-11-25 13:16:00 -08:00
zach
9134635b37 cleanup: return better errors for wasi command modules (#793) 2024-11-25 08:49:57 -08:00
dependabot[bot]
75428f26e2 chore(deps): Bump dawidd6/action-download-artifact from 2 to 6 in /.github/workflows (#792)
Bumps
[dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
from 2 to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dawidd6/action-download-artifact/releases">dawidd6/action-download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v6</h2>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v5...v6">https://github.com/dawidd6/action-download-artifact/compare/v5...v6</a></p>
<h2>v5</h2>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v4...v5">https://github.com/dawidd6/action-download-artifact/compare/v4...v5</a></p>
<h2>v4</h2>
<h2>What's Changed</h2>
<ul>
<li><strong>VERSIONING CHANGE</strong>: now there will only be major
releases of this action, e.g. v5, v6 and so on</li>
<li>build(deps): bump undici from 5.28.3 to 5.28.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/284">dawidd6/action-download-artifact#284</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.4 to
2.1.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/285">dawidd6/action-download-artifact#285</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.5 to
2.1.7 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/287">dawidd6/action-download-artifact#287</a></li>
<li>build(deps): bump adm-zip from 0.5.12 to 0.5.13 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/289">dawidd6/action-download-artifact#289</a></li>
<li>Set allow_forks to false by default by <a
href="https://github.com/timweri"><code>@​timweri</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/290">dawidd6/action-download-artifact#290</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/timweri"><code>@​timweri</code></a> made
their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/290">dawidd6/action-download-artifact#290</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3...v4">https://github.com/dawidd6/action-download-artifact/compare/v3...v4</a></p>
<h2>v3.1.4</h2>
<h2>What's Changed</h2>
<ul>
<li>build(deps): bump adm-zip from 0.5.10 to 0.5.12 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/282">dawidd6/action-download-artifact#282</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.2 to
2.1.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/280">dawidd6/action-download-artifact#280</a></li>
<li>fix: accept expired artifacts with documentation url by <a
href="https://github.com/wdconinc"><code>@​wdconinc</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/283">dawidd6/action-download-artifact#283</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/wdconinc"><code>@​wdconinc</code></a>
made their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/283">dawidd6/action-download-artifact#283</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3...v3.1.4">https://github.com/dawidd6/action-download-artifact/compare/v3...v3.1.4</a></p>
<h2>v3.1.3</h2>
<h2>What's Changed</h2>
<ul>
<li>node_modules: upgrade by <a
href="https://github.com/dawidd6"><code>@​dawidd6</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/276">dawidd6/action-download-artifact#276</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.1 to
2.1.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/277">dawidd6/action-download-artifact#277</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3.1.2...v3.1.3">https://github.com/dawidd6/action-download-artifact/compare/v3.1.2...v3.1.3</a></p>
<h2>v3.1.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Read workflow_search input as a boolean by <a
href="https://github.com/klutchell"><code>@​klutchell</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/273">dawidd6/action-download-artifact#273</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/klutchell"><code>@​klutchell</code></a>
made their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/273">dawidd6/action-download-artifact#273</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3.1.1...v3.1.2">https://github.com/dawidd6/action-download-artifact/compare/v3.1.1...v3.1.2</a></p>
<h2>v3.1.1</h2>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bf251b5aa9"><code>bf251b5</code></a>
node_modules: upgrade</li>
<li><a
href="93c6296611"><code>93c6296</code></a>
README: v5</li>
<li><a
href="deb3bb8325"><code>deb3bb8</code></a>
node_modules: upgrade</li>
<li><a
href="1d93f37db2"><code>1d93f37</code></a>
README: v4</li>
<li><a
href="854e2de939"><code>854e2de</code></a>
Set allow_forks to false by default (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/290">#290</a>)</li>
<li><a
href="436c9d3774"><code>436c9d3</code></a>
build(deps): bump adm-zip from 0.5.12 to 0.5.13 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/289">#289</a>)</li>
<li><a
href="14040524bb"><code>1404052</code></a>
build(deps): bump <code>@​actions/artifact</code> from 2.1.5 to 2.1.7
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/287">#287</a>)</li>
<li><a
href="8a9be734dc"><code>8a9be73</code></a>
build(deps): bump <code>@​actions/artifact</code> from 2.1.4 to 2.1.5
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/285">#285</a>)</li>
<li><a
href="df593bbd04"><code>df593bb</code></a>
build(deps): bump undici from 5.28.3 to 5.28.4 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/284">#284</a>)</li>
<li><a
href="09f2f74827"><code>09f2f74</code></a>
fix: accept expired artifacts with documentation url (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/283">#283</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/dawidd6/action-download-artifact/compare/v2...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dawidd6/action-download-artifact&package-manager=github_actions&previous-version=2&new-version=6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/extism/extism/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-25 07:50:29 -08:00
Steve Manuel
7beeee35f1 feat: add overview on generating bindings (#789)
Primarily adds the Generating Bindings section, but also updates the PDK
and SDK list to include more languages.
2024-11-19 22:48:00 -08:00
Chris Dickinson
6cf8251d90 v1.9.0 2024-11-19 14:11:47 -08:00
zach
4d0799ca37 docs: add comment to fs example (#788)
Since it's using a read-only path, we should provide some information
about how to use a read/write path to make this program run without
failing.
2024-11-15 18:21:29 -08:00
zach
14477ceb39 feat: add CompiledPlugin (#784) 2024-11-14 12:32:22 -08:00
zach
af67a6990c chore: update to wasmtime 26 (#783) 2024-11-07 12:36:58 -08:00
zach
72c47fceaf v1.8.0 2024-10-22 09:39:13 -07:00
Benjamin Eckel
f52969aadb Add codeowners file (#780) 2024-10-22 09:35:04 -07:00
zach
7775c57a81 fix: use f32::to_bits and f64::to_bits when constructing Val (#779)
Fixes #739
2024-10-22 09:33:04 -07:00
zach
7b6664d019 feat: add ability to access response headers when using extism:host/env::http_request (#774)
- Adds `extism:host/env::http_headers` to access HTTP response headers
- Adds `PluginBuilder::with_http_response_headers` to enable response
headers from Rust
- Adds `extism_plugin_allow_http_response_headers` to enable response
headers using the C API

TODO:
- [x] Update a PDK to use `extism:host/env::http_headers` so I can test
this
2024-10-14 10:09:28 -07:00
Gavin Hayes
a91846a34b fix(plugin_call): set rc to EXIT_SIGNALED_SIGABRT when wasmtime bails out on plugin call (#776)
Fixes #775

134/EXIT_SIGNALED_SIGABRT was chosen as the wasmtime CLI exits with it
executes `unreachable`.
2024-10-10 15:03:59 -04:00
Han Yang
876a3be147 Fix: no method named free found for mutable reference &mut current_plugin::CurrentPlugin in the current scope (#773)
think there's a typo for this block when the `http` feature is disabled
2024-10-04 07:48:29 -07:00
zach
520d72e408 v1.7.0 2024-09-24 10:17:01 -07:00
zach
3ac3d9abcf cleanup: host takes ownership of memory blocks it gets as arguments (#743)
This PR changes the host to take ownership of memory blocks passed into
Extism host functions, see:
https://github.com/extism/js-sdk/pull/71#issuecomment-2233687933
2024-09-23 10:42:45 -07:00
SebastianHambura
8222164eca Adds more details about with_wasmtime_config() limitations (#770)
PR for https://github.com/extism/extism/pull/764#issuecomment-2368337805

---------

Co-authored-by: Sebastian Hambura <sebastian.hambur@embl.de>
2024-09-23 08:04:29 -07:00
zach
fa81270a5f cleanup(kernel): only try to re-use free blocks before memory.grow (#765)
Updates the kernel to only scan for free blocks before a `memory.grow`
operation, this should improve performance of `alloc` by not iterating
over every block for each allocation.
2024-09-19 15:55:02 -07:00
zach
7bf41c2c7f feat: add PluginBuilder::with_wasmtime_config (#764)
An alternative to #763, this PR allows an initial `wasmtime::Config` to
be passed in when building a plugin. Some of these values may be
overwritten by the Extism runtime, but it allows for things like static
memory size and other low-level details to be handled directly instead
of us having to wrap every option ourselves.
2024-09-19 11:27:27 -07:00
Fabien Benetou
d3a68e2c0c chore: define pdk term in README (#766)
from https://extism.org/docs/concepts/pdk
2024-09-19 08:53:18 -06:00
zach
e31806cdb1 v1.6.0 2024-09-04 12:23:21 -07:00
zach
c2866a7358 fix: better error handling when plugin runs out of fuel (#762)
- Checks error results to determine if a plugin ran out of fuel, if the
fuel is 0 after we get the error, then we return an out of fuel error
message instead.
- Updates `extism_plugin_error` to check `Plugin::error_msg` regardless
of the kernel's error state
2024-09-04 09:42:09 -07:00
Edoardo Vacchi
34096bd9c0 fix: Vec.as_ptr() might return a dangling pointer (#760)
Both [as_ptr][as_ptr] and [as_mut_ptr][as_mut_ptr] are allowed to return
a dangling raw pointer when the Vec size is 0.

The idea is that you should guard that read checking the size. This
probably works well in most cases, but at the very least in the
java-sdk, the JNA machinery tries to be helpful and it dereferences the
pointer, causing a SIGSEGV.

The solution is to check if the resulting vector is empty and return
null instead. A new, empty vector would be better, but I think that
would not solve the problem, because the problem is caused by a new,
empty vector in the first place.

Caveat: this might break consumers downstream.
On the other hand: consumers that do not check for the nInput, nOutput
counts are just waiting to explode, like JNA.

This addresses https://github.com/extism/java-sdk/issues/27

[as_ptr]:
https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_ptr
[as_mut_ptr]:
https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_mut_ptr

Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com>
2024-09-04 09:41:55 -07:00
zach
d2a3699f43 fix: avoid creating too many externrefs (#759)
Updates plugins to allocate a single `ExternRef` for the host context up
front, to avoid running into the `failed to allocate externref` error
from Wasmtime
2024-08-29 17:24:18 -07:00
Steve Manuel
b6e1caad07 feat(runtime): add log level set/get for pdk control (#758)
Co-authored-by: zach <zach@dylibso.com>
2024-08-28 14:31:55 -06:00
zach
e979987dc7 feat: add ability to limit the number of instructions executed by a plugin (#754)
*Note*: this will be limited for the time being as not all runtimes
support this yet
2024-08-23 10:24:28 -07:00
zach
ef2eeab6e3 chore: include support for wasmtime 23.0.0 (#755) 2024-08-22 12:49:58 -07:00
dependabot[bot]
9da8088ebf chore(deps): Update prost requirement from 0.12.0 to 0.13.1 (#741)
Updates the requirements on [prost](https://github.com/tokio-rs/prost)
to permit the latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tokio-rs/prost/blob/master/CHANGELOG.md">prost's
changelog</a>.</em></p>
<blockquote>
<h1>Prost version 0.13.1</h1>
<p><em>PROST!</em> is a <a
href="https://developers.google.com/protocol-buffers/">Protocol
Buffers</a> implementation for the <a
href="https://www.rust-lang.org/">Rust Language</a>. <code>prost</code>
generates simple, idiomatic Rust code from <code>proto2</code> and
<code>proto3</code> files.</p>
<h2>Bug fixes</h2>
<ul>
<li>Enum variant named Error causes ambiguous item (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1098">#1098</a>)</li>
</ul>
<h1>PROST version 0.13.0</h1>
<p><strong>note</strong>: this version was yanked in favor of 0.13.1</p>
<p><em>PROST!</em> is a <a
href="https://developers.google.com/protocol-buffers/">Protocol
Buffers</a> implementation for the <a
href="https://www.rust-lang.org/">Rust Language</a>. <code>prost</code>
generates simple, idiomatic Rust code from <code>proto2</code> and
<code>proto3</code> files.</p>
<p>This major update brings new features and fixes:</p>
<h2>Breaking changes</h2>
<ul>
<li>
<p>derive Copy trait for messages where possible (<a
href="https://redirect.github.com/tokio-rs/prost/issues/950">#950</a>)</p>
<p><code>prost-build</code> will automatically derive <code>trait
Copy</code> for some messages. If you manually implement
<code>Copy</code> you should remove your implementation.</p>
</li>
<li>
<p>Change generated functions signatures to remove type parameters (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1045">#1045</a>)</p>
<p>The function signature of <code>trait Message</code> is changed to
use <code>impl Buf</code> instead of a named generic type. If you
implement <code>trait Message</code>, you should change the function
signature.</p>
</li>
<li>
<p>Lightweight error value in TryFrom<!-- raw HTML omitted --> for enums
(<a
href="https://redirect.github.com/tokio-rs/prost/issues/1010">#1010</a>)</p>
<p>When a <code>impl TryFrom&lt;i32&gt;</code> is generated by
<code>prost</code> derive macros, it will now return the error type
<code>UnknownEnumValue</code> instead of <code>DecodeError</code>. The
new error can be used to retreive the integer value that failed to
convert.</p>
</li>
</ul>
<h2>Features</h2>
<ul>
<li>
<p>fix: Only touch include file if contents is changed (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1058">#1058</a>)</p>
<p>Most generated files are untouched when the contents doesn't change.
Use the same mechanism for include file as well.</p>
</li>
</ul>
<h2>Dependencies</h2>
<ul>
<li>update env_logger requirement from 0.10 to 0.11 (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1074">#1074</a>)</li>
<li>update criterion requirement from 0.4 to 0.5 (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1071">#1071</a>)</li>
<li>Remove unused libz-sys (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1077">#1077</a>)</li>
<li>build(deps): update itertools requirement from &gt;=0.10, <!-- raw
HTML omitted -->=0.10, &lt;=0.13 (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1070">#1070</a>)</li>
</ul>
<h2>Documentation</h2>
<ul>
<li>better checking of tag duplicates, avoid discarding invalid variant
errs (<a
href="https://redirect.github.com/tokio-rs/prost/issues/951">#951</a>)</li>
<li>docs: Fix broken link warnings (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1056">#1056</a>)</li>
<li>Add missing LICENSE symlink (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1086">#1086</a>)</li>
</ul>
<h2>Internal</h2>
<ul>
<li>workspace package metadata (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1036">#1036</a>)</li>
<li>fix: Build error due to merge conflict (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1068">#1068</a>)</li>
<li>build: Fix release scripts (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1055">#1055</a>)</li>
<li>chore: Add ci to check MSRV (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1057">#1057</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f19104a3d4"><code>f19104a</code></a>
chore: prepare 0.13.1 release (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1099">#1099</a>)</li>
<li><a
href="26463f437e"><code>26463f4</code></a>
fix: Enum variant named <code>Error</code> causes ambiguous item (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1098">#1098</a>)</li>
<li><a
href="23f7174969"><code>23f7174</code></a>
chore: Release version 0.13.0 (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1093">#1093</a>)</li>
<li><a
href="7a1424cf8c"><code>7a1424c</code></a>
build: Fix prepare-release.sh (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1094">#1094</a>)</li>
<li><a
href="7790799b0d"><code>7790799</code></a>
build(deps): update itertools requirement from &gt;=0.10, &lt;=0.12 to
&gt;=0.10, &lt;=0....</li>
<li><a
href="4a0cc17102"><code>4a0cc17</code></a>
Add missing LICENSE symlink (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1086">#1086</a>)</li>
<li><a
href="ae33a5ea97"><code>ae33a5e</code></a>
ci: Set rust version of clippy job to a fixed version (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1090">#1090</a>)</li>
<li><a
href="ba77654083"><code>ba77654</code></a>
fix: Only touch include file if contents is changed (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1058">#1058</a>)</li>
<li><a
href="e7049d3eb2"><code>e7049d3</code></a>
workspace package metadata (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1036">#1036</a>)</li>
<li><a
href="ef4930c140"><code>ef4930c</code></a>
docs: Fix broken link warnings (<a
href="https://redirect.github.com/tokio-rs/prost/issues/1056">#1056</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tokio-rs/prost/compare/v0.12.0...v0.13.1">compare
view</a></li>
</ul>
</details>
<br />


You can trigger a rebase of this PR 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>

> **Note**
> Automatic rebases have been disabled on this pull request as it has
been open for over 30 days.

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-22 12:49:18 -07:00
dependabot[bot]
7c60b9340a chore(deps): Update cbindgen requirement from 0.26 to 0.27 (#752)
Updates the requirements on
[cbindgen](https://github.com/mozilla/cbindgen) to permit the latest
version.
<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.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
  * Update MSRV to 1.57
* Support variadic arguments (`...`)
([#805](https://github.com/mozilla/cbindgen/issues/805))
* Add --depfile option
([#820](https://github.com/mozilla/cbindgen/issues/820))
  * Breaking changes: The `Config` struct now has a private member.
</code></pre>
<h2>0.24.6 (YANKED: depfile option was breaking, see <a
href="https://redirect.github.com/mozilla/cbindgen/issues/841">#841</a>)</h2>
<pre><code>  * Update MSRV to 1.57
* Support variadic arguments (`...`)
([#805](https://github.com/mozilla/cbindgen/issues/805))
* Add --depfile option
([#820](https://github.com/mozilla/cbindgen/issues/820))
</code></pre>
<h2>0.24.5</h2>
<pre><code>  * Don't enforce tempfile version.
</code></pre>
<h2>0.24.4</h2>
<pre><code> * Move expand infinite recursion fix
([#799](https://github.com/mozilla/cbindgen/issues/799))
* Add with_cpp_compat to the builder
([#796](https://github.com/mozilla/cbindgen/issues/796))
* Handle never type in return position consistently
([#780](https://github.com/mozilla/cbindgen/issues/780))
* Fix warnings ([#816](https://github.com/mozilla/cbindgen/issues/816),
[#819](https://github.com/mozilla/cbindgen/issues/819))
* Updated documentation
([#788](https://github.com/mozilla/cbindgen/issues/788),
[#791](https://github.com/mozilla/cbindgen/issues/791),
[#792](https://github.com/mozilla/cbindgen/issues/792),
[#810](https://github.com/mozilla/cbindgen/issues/810),
[#823](https://github.com/mozilla/cbindgen/issues/823))
</code></pre>
<h2>0.24.3</h2>
<pre><code> * Make struct expressions correctly generated through
typedefs ([#768](https://github.com/mozilla/cbindgen/issues/768)).
</code></pre>
<h2>0.24.2</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="58c6156b0d"><code>58c6156</code></a>
Bump MSRV again for clap.</li>
<li><a
href="103a8de0ac"><code>103a8de</code></a>
Cargo update and version bump.</li>
<li><a
href="67cb560430"><code>67cb560</code></a>
Update CHANGES since v0.26.0</li>
<li><a
href="316298182e"><code>3162981</code></a>
Output condition for globals.</li>
<li><a
href="e469e44c00"><code>e469e44</code></a>
Add missing parens to log message</li>
<li><a
href="3cbb637bbf"><code>3cbb637</code></a>
Update cython expectations from the previous patch.</li>
<li><a
href="785e066e03"><code>785e066</code></a>
Fix variadic arguments when used in function pointer</li>
<li><a
href="aa8ea654e1"><code>aa8ea65</code></a>
deps: Update syn to 2.0</li>
<li><a
href="9f632843b8"><code>9f63284</code></a>
Generalize Item to expose documentation and generic params</li>
<li><a
href="1dda6162e5"><code>1dda616</code></a>
Used documented method of specifying variadic arguments</li>
<li>Additional commits viewable in <a
href="https://github.com/mozilla/cbindgen/compare/0.26.0...v0.27.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>
2024-08-22 12:27:18 -07:00
Gavin Hayes
00074fd56d feat: add releasing x86_64-unknown-linux-musl dynamic library (#753)
Fixes https://github.com/extism/extism/issues/735
2024-08-19 14:46:08 -04:00
zach
f0c9640e1e cleanup: allow shadowing host functions (#751) 2024-08-08 13:20:40 -07:00
innuendo
d48dc4021c feat(runtime): support log_trace in rust-sdk (#747)
Add support for logtrace in Rust SDK runtime.

Fix `clippy::needless_borrows_for_generic_args` lints.

Ref: https://github.com/extism/extism/issues/744

Co-authored-by: corda.ilaria@gmail.com <ilariac691@gmail.com>
Co-authored-by: Steve Manuel <steve@dylibso.com>
Co-authored-by: Chris Dickinson <chris@dylibso.com>
2024-07-30 11:53:23 -07:00
Steve Manuel
10e44c0006 chore: use more comprehensive crate source 2024-07-30 10:07:49 -06:00
Muhammad Azeez
b7fa319cb9 Add readonly dirs to allowed_paths (#733)
This is a rough POC for allowing people to whitelist a dir as readonly.
When the source path is prefixed with `ro:`, the dir is considered as
readonly. This preserved backward compatibility. This suggestion came up
in https://github.com/extism/go-sdk/pull/1#discussion_r1276700587

Readonly:
```rs
let manifest = Manifest::new([url])
        .with_allowed_path("ro:D:/x/rust/fs/data".to_string(), "/data")
        .with_config_key("path", "/data/data.txt");
```

```
trying to read file:
"Hello World at 1719851282.5109031sHello World at 1719851299.0819795sHello World at 1719851317.8934608s\n"
-----------------------------------------------------
trying to write file:
thread '<unnamed>' panicked at src\lib.rs:24:34:
called `Result::unwrap()` on an `Err` value: Os { code: 58, kind: Unsupported, message: "Not supported" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at runtime\examples\fs.rs:27:6:
called `Result::unwrap()` on an `Err` value: error while executing at wasm backtrace:
    0: 0x234d2 - fs.wasm!__rust_start_panic
    1: 0x232a1 - fs.wasm!rust_panic
    2: 0x231da - fs.wasm!std::panicking::rust_panic_with_hook::hd3fb69bc0aea298a
    3: 0x22467 - fs.wasm!std::panicking::begin_panic_handler::{{closure}}::h4d99b90b43f79472
    4: 0x223ca - fs.wasm!std::sys_common::backtrace::__rust_end_short_backtrace::h5691573a73161cb1
    5: 0x22bca - fs.wasm!rust_begin_unwind
    6: 0x303e9 - fs.wasm!core::panicking::panic_fmt::hdb62f5cdb45533e4
    7: 0x3234d - fs.wasm!core::result::unwrap_failed::h30d23efcc9e41efc
    8: 0x36c2 - fs.wasm!fs::try_write::inner::h0b3b0df8e129f5cc
    9: 0x29cd - fs.wasm!try_write
   10: 0x35e4a - fs.wasm!try_write.command_export
note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information

Caused by:
    wasm trap: wasm `unreachable` instruction executed

Stack backtrace:
   0: std::backtrace_rs::backtrace::dbghelp64::trace
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\..\..\backtrace\src\backtrace\dbghelp64.rs:99
   1: std::backtrace_rs::backtrace::trace_unsynchronized
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\..\..\backtrace\src\backtrace\mod.rs:66
   2: std::backtrace::Backtrace::create
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\backtrace.rs:331
   3: std::backtrace::Backtrace::capture
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\backtrace.rs:296
   4: anyhow::error::impl$1::from<wasmtime_environ::trap_encoding::Trap>
             at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\anyhow-1.0.86\src\error.rs:565
   5: core::convert::impl$3::into<wasmtime_environ::trap_encoding::Trap,anyhow::Error>
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\convert\mod.rs:759
   6: wasmtime_environ::impl$1::into_anyhow<wasmtime_environ::trap_encoding::Trap>
             at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-environ-22.0.0\src\lib.rs:90
   7: wasmtime::runtime::trap::from_runtime_box
             at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\trap.rs:118
   8: wasmtime::runtime::func::invoke_wasm_and_catch_traps::closure$0<extism::current_plugin::CurrentPlugin,wasmtime::runtime::func::impl$1::call_unchecked_raw::closure_env$0<extism::current_plugin::CurrentPlugin> >
             at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1597
   9: enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<wasmtime::runtime::vm::traphandlers::Trap,alloc::alloc::Global> > >::map_err<tuple$<>,alloc::boxed::Box<wasmtime::runtime::vm::traphandlers::Trap,alloc::alloc::Global>,anyhow::Error,wasmtime::runtime:
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\result.rs:829
  10: wasmtime::runtime::func::invoke_wasm_and_catch_traps<extism::current_plugin::CurrentPlugin,wasmtime::runtime::func::impl$1::call_unchecked_raw::closure_env$0<extism::current_plugin::CurrentPlugin> >
             at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1597
  11: wasmtime::runtime::func::Func::call_unchecked_raw<extism::current_plugin::CurrentPlugin>
             at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1063
  12: wasmtime::runtime::func::Func::call_unchecked<ref_mut$<wasmtime::runtime::store::context::StoreContextMut<extism::current_plugin::CurrentPlugin> > >
             at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1049
  13: wasmtime::runtime::func::Func::call_impl_do_call<extism::current_plugin::CurrentPlugin>
             at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1243
  14: wasmtime::runtime::func::Func::call<ref_mut$<wasmtime::runtime::store::Store<extism::current_plugin::CurrentPlugin> > >
             at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1002
  15: extism::plugin::Plugin::raw_call<ref$<str$>,ref$<str$> >
             at .\src\plugin.rs:753
  16: extism::plugin::Plugin::call<ref$<str$>,ref$<str$>,ref$<str$> >
             at .\src\plugin.rs:900
  17: fs::main
             at .\examples\fs.rs:25
  18: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\ops\function.rs:250
  19: core::hint::black_box
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\hint.rs:337
  20: std::sys_common::backtrace::__rust_begin_short_backtrace<void (*)(),tuple$<> >
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\std\src\sys_common\backtrace.rs:155
  21: std::rt::lang_start::closure$0<tuple$<> >
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\std\src\rt.rs:166
  22: std::rt::lang_start_internal
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\rt.rs:148
  23: std::rt::lang_start<tuple$<> >
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\std\src\rt.rs:165
  24: main
  25: invoke_main
             at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
  26: __scrt_common_main_seh
             at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
  27: BaseThreadInitThunk
  28: RtlUserThreadStart
stack backtrace:
   0: std::panicking::begin_panic_handler
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\panicking.rs:645
   1: core::panicking::panic_fmt
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\core\src\panicking.rs:72
   2: core::result::unwrap_failed
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\core\src\result.rs:1654
   3: enum2$<core::result::Result<ref$<str$>,anyhow::Error> >::unwrap
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\result.rs:1077
   4: fs::main
             at .\examples\fs.rs:25
   5: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\ops\function.rs:250
   6: core::hint::black_box
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\hint.rs:337
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: process didn't exit successfully: `D:\dylibso\extism\target\debug\examples\fs.exe` (exit code: 101)
```

Writable:
```rs
    let manifest = Manifest::new([url])
        .with_allowed_path("D:/x/rust/fs/data".to_string(), "/data")
        .with_config_key("path", "/data/data.txt");

```

```
trying to read file:
"Hello World at 1719851282.5109031sHello World at 1719851299.0819795sHello World at 1719851317.8934608s\n"
-----------------------------------------------------
trying to write file:
"Hello World at 1719851282.5109031sHello World at 1719851299.0819795sHello World at 1719851317.8934608s\nHello World at 1719851500.7803263s\n"
done!
```
2024-07-25 19:40:38 +03:00
zach
d04e2e42bf v1.5.0 2024-07-23 11:07:02 -07:00
zach
6d2735cec7 fix: require error messages to be null terminated in C SDK (#745)
Related to https://github.com/extism/python-sdk/issues/23 - there is
currently no way to get the length of the error message, so we need to
make sure it is a valid C string.
2024-07-23 09:35:59 -07:00
zach
b1d0f335b3 doc: fix usage of host_fn macro in doc example (#742) 2024-07-16 16:40:27 -07:00
Steve Manuel
3a7768ffd5 chore: update readme with crate version (#738) 2024-07-11 07:58:06 -05:00
zach
ee8c41ab26 doc: more information about error_set (#737) 2024-07-10 12:43:37 -07:00
zach
8312e98463 test: add benchmark for creating a plugin with the cache disabled (#736) 2024-07-10 11:18:08 -07:00
zach
17a546b2db chore: support for wasmtime 22 (#731) 2024-06-21 18:17:28 -07:00
zach
6a18512fc0 v1.4.1 2024-06-14 10:12:55 -07:00
Gavin Hayes
8a95a18920 docs: add CPAN link for perl-sdk (#729) 2024-06-14 12:32:51 -04:00
zach
9dbc22830e fix: use wasi-common to avoid issues with tokio (#728)
See https://github.com/bytecodealliance/wasmtime/issues/8799

I will make a 1.4.1 release after this is merged
2024-06-14 09:22:55 -07:00
zach
c3e912dffb v1.4.0 2024-06-12 15:17:45 -07:00
Gavin Hayes
c4b82e3eda fix(libextism): improve static linking pkgconfig (#726)
This includes three fixes:

* link static library by absolute path (should fix static linking on
Mac/ with `lld`)
* link static library with `-framework Security` on Mac
* link `libpthread` , this should be a no-op on systems with modern
libc, but should fix static linking on systems with glibc pre 2.34 see
https://developers.redhat.com/articles/2021/12/17/why-glibc-234-removed-libpthread
and error
http://www.cpantesters.org/cpan/report/669fdfc8-25a4-11ef-9502-51fb6d8775ea

---------

Co-authored-by: zach <zachshipko@gmail.com>
Co-authored-by: zach <zach@dylibso.com>
2024-06-11 16:22:55 -04:00
zach
2a7345a480 fix: return error when non-zero exit code in returned (#727)
Returns an error when a plugin call returns a non-zero exit code

See https://github.com/extism/go-pdk/issues/33
2024-06-11 12:34:10 -07:00
Gavin Hayes
9099cc73c5 fix(libextism): examples and docs (#724)
Big thanks to @konsumer for reporting the issues!
2024-06-07 14:42:20 -04:00
zach
3f54892a39 refactor!: update to wasmtime 20 or greater (#723)
- Breaking: No longer copies Extism config values into WASI environment
variables because the new interface doesn't allow for the environment to
be updated - these should be accessed using the Extism config functions
instead
- Requires wasmtime 20 or greater
- Enables wasm-gc
- Similar to https://github.com/extism/extism/pull/697 without sockets
or additional support for command modules
2024-06-05 12:57:25 -07:00
zach
ecf18a2d81 fix: re-use linking code from Plugin::new in Plugin::reset_store (#722) 2024-05-31 08:25:06 -07:00
zach
9bc1fc73f2 chore: rename kernel/.cargo/config to kernel/.cargo/config.toml (#721) 2024-05-28 18:26:19 -07:00
zach
2bf391f236 doc: update API.md for latest changes (#720) 2024-05-28 09:27:17 -07:00
Muhammad Azeez
5da0eb38ec refactor: remove HttpRequest.header alias (#718)
https://github.com/extism/dotnet-pdk/pull/84 brought to my attention
that the Rust SDK supports both `headers` and `header` while the go sdk
only supports `headers`. After talking to Zach, we decided to remove the
`header` alias from the Rust SDK too, since it's obsolete and we want
people to use `headers`
2024-05-22 20:34:35 +03:00
zach
7cb6c53910 v1.3.0 2024-05-22 10:07:06 -07:00
zach
0882f35300 fix: respect overall timeout when using http requests (#717)
Currently HTTP requests can extend beyond the configured timeout for a
plugin - this PR sets the timeout of the HTTP request to the remaining
time left if a timeout is set in the manifest.
2024-05-21 20:11:00 -07:00
Chris Dickinson
5d9c8c5d05 feat: per call context (#711)
Add `plugin.call_with_host_context` and `current_plugin.host_context`
methods, enabling per-call context to be looped from the guest invocation
to any host functions it calls. In an HTTP server environment, this enables
re-using a plugin across multiple requests while switching out backing
connections and user information in host functions. (Imagine a host
function, `update_user` -- previously the plugin would have to have been
aware of the user to pass to the host function. Now that information is
ambient.)

This is a backwards-compatible change and requires no changes to
existing plugins.

Implement by adding a global, mutable externref to the extism kernel.
Since most programming languages, including Rust, don't let you define
these natively, we accomplish this by using `wasm-merge` to combine the
kernel Wasm with Wasm generated by a WAT file containing only the
global.

(This pattern might be useful for other Wasm constructs we can't use
directly from Rust, like `v128` in argument parameters.)

Wasmtime requires extern refs to be `Any + Send + Sync + 'static`; we
additionally add `Clone`. I haven't tried this with an `Arc` directly,
but it should work at least for container structs that hold `Arc`'s
themselves.
2024-05-21 11:53:43 -07:00
Gavin Hayes
75e92c40a0 fix(libextism): namespace ExtismValType (#715)
Some of the old constants conflicted with Perl headers used for build
Perl extensions such the
[perl-sdk](002e4437ac/Extism/lib/Extism/XS.xs).
This fix would allow removing the copy of extism.h (inlined in that file
linked) out of the perl-sdk.

These constants especially `I32` likely have conflicts with many other
large C codebases.

A new extism release with this fix should not be made until the affected
sdks (cpp-sdk) have an update ready.
2024-05-20 11:58:04 -04:00
Benjamin Eckel
5373f7d88d docs: Add more context to linking example (#707)
Just adding more context in response to an inquiry about how this works.
2024-04-28 15:11:39 -05:00
Roland Fredenhagen
c5a23a31d8 feat: add id() to CurrentPlugin (#705)
fixes  #704
2024-04-15 09:03:48 -07:00
Steve Manuel
7206e2b362 chore: add perl-sdk to README list 2024-04-10 22:43:27 -06:00
Steve Manuel
20f551f019 chore: fix broken links in crate readme (#701) 2024-04-04 10:23:46 -06:00
zach
9aa817def7 cleanup: add paths to errors, clippy (#700) 2024-03-27 14:54:03 -07:00
zach
054a29e91d v1.2.0 2024-03-12 08:52:04 -07:00
zach
d32d4a3dd7 fix(pdk): return error when no response is available (#694) 2024-03-11 10:32:31 -07:00
Steve Manuel
5f62554aa1 chore: update badge to reflect rust installs (#693) 2024-03-08 11:29:07 -07:00
zach
d47af24552 feat: add ability to configure size of the Extism var store (#692)
- Adds `memory.max_var_bytes` to the manifest to limit the number of
bytes allowed to be stored in Extism vars - if `max_var_bytes` is set to
0 then vars are disabled.
- Adds some builder functions to `MemoryOptions` struct
- Sets the default var store size to 1mb
- Includes a test to make sure `var_set` returns an error when the limit
is reached
2024-03-07 09:55:02 -08:00
dependabot[bot]
8a29e5b1d4 chore(deps): Update base64 requirement from ~0.21 to ~0.22 (#690)
Updates the requirements on
[base64](https://github.com/marshallpierce/rust-base64) to permit the
latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md">base64's
changelog</a>.</em></p>
<blockquote>
<h1>0.22.0</h1>
<ul>
<li><code>DecodeSliceError::OutputSliceTooSmall</code> is now
conservative rather than precise. That is, the error will only occur if
the decoded output <em>cannot</em> fit, meaning that
<code>Engine::decode_slice</code> can now be used with exactly-sized
output slices. As part of this, <code>Engine::internal_decode</code> now
returns <code>DecodeSliceError</code> instead of
<code>DecodeError</code>, but that is not expected to affect any
external callers.</li>
<li><code>DecodeError::InvalidLength</code> now refers specifically to
the <em>number of valid symbols</em> being invalid (i.e. <code>len % 4
== 1</code>), rather than just the number of input bytes. This avoids
confusing scenarios when based on interpretation you could make a case
for either <code>InvalidLength</code> or <code>InvalidByte</code> being
appropriate.</li>
<li>Decoding is somewhat faster (5-10%)</li>
</ul>
<h1>0.21.7</h1>
<ul>
<li>Support getting an alphabet's contents as a str via
<code>Alphabet::as_str()</code></li>
</ul>
<h1>0.21.6</h1>
<ul>
<li>Improved introductory documentation and example</li>
</ul>
<h1>0.21.5</h1>
<ul>
<li>Add <code>Debug</code> and <code>Clone</code> impls for the general
purpose Engine</li>
</ul>
<h1>0.21.4</h1>
<ul>
<li>Make <code>encoded_len</code> <code>const</code>, allowing the
creation of arrays sized to encode compile-time-known data lengths</li>
</ul>
<h1>0.21.3</h1>
<ul>
<li>Implement <code>source</code> instead of <code>cause</code> on Error
types</li>
<li>Roll back MSRV to 1.48.0 so Debian can continue to live in a time
warp</li>
<li>Slightly faster chunked encoding for short inputs</li>
<li>Decrease binary size</li>
</ul>
<h1>0.21.2</h1>
<ul>
<li>Rollback MSRV to 1.57.0 -- only dev dependencies need 1.60, not the
main code</li>
</ul>
<h1>0.21.1</h1>
<ul>
<li>Remove the possibility of panicking during decoded length
calculations</li>
<li><code>DecoderReader</code> no longer sometimes erroneously ignores
padding <a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/226">#226</a></li>
</ul>
<h2>Breaking changes</h2>
<ul>
<li><code>Engine.internal_decode</code> return type changed</li>
<li>Update MSRV to 1.60.0</li>
</ul>
<h1>0.21.0</h1>
<h2>Migration</h2>
<h3>Functions</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="5d70ba7576"><code>5d70ba7</code></a>
Merge pull request <a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/269">#269</a>
from marshallpierce/mp/decode-precisely</li>
<li><a
href="efb6c006c7"><code>efb6c00</code></a>
Release notes</li>
<li><a
href="2b91084a31"><code>2b91084</code></a>
Add some tests to boost coverage</li>
<li><a
href="9e9c7abe65"><code>9e9c7ab</code></a>
Engine::internal_decode now returns DecodeSliceError</li>
<li><a
href="a8a60f43c5"><code>a8a60f4</code></a>
Decode main loop improvements</li>
<li><a
href="a25be0667c"><code>a25be06</code></a>
Simplify leftover output writes</li>
<li><a
href="9979cc33bb"><code>9979cc3</code></a>
Keep morsels as separate bytes</li>
<li><a
href="37670c5ec2"><code>37670c5</code></a>
Bump dev toolchain version (<a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/268">#268</a>)</li>
<li><a
href="9652c78773"><code>9652c78</code></a>
v0.21.7</li>
<li><a
href="08deccf703"><code>08deccf</code></a>
provide as_str() method to return the alphabet characters (<a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/264">#264</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/marshallpierce/rust-base64/compare/v0.21.0...v0.22.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>
2024-03-04 09:04:37 -08:00
zach
4e0cd3b1cf doc: remove old default for timeout_ms (#688) 2024-02-26 16:29:35 -08:00
zach
f4013c5ac0 fix: circular dependencies 2024-02-22 14:04:01 -08:00
zach
ddc339334e fix: remove readme field 2024-02-22 13:07:06 -08:00
zach
ff5b714f95 v1.1.0 2024-02-22 11:01:19 -08:00
zach
ed1439ec2d fix: linker issue that depends on the ordering of the linked functions (#685)
It looks like when a module is added to the linker, all of its imports
must already be present. This PR updates the linking process to take
that into consideration and adds a test with a reproduction of the issue
@chrisdickinson shared with me.
2024-02-22 10:56:21 -08:00
zach
62f0a231b0 ci: add release workflow for convert-macros crate (#683) 2024-02-14 09:18:28 -08:00
zach
fc22412ff0 feat: allow max HTTP response size to be configured in the manifest (#674)
- Adds `memory.max_http_response_bytes` field to specify the maximum
size of an HTTP request response
2024-02-07 14:31:23 -08:00
Roland Fredenhagen
1a083f612a feat(convert): add derive macros for To and FromBytes (#667)
closes #661.

- [x] docs
- [x] tests
- [x] depend on `extism-convert/extism-pdk-path` feature in
https://github.com/extism/rust-pdk
https://github.com/extism/rust-pdk/pull/47
2024-02-05 15:59:55 -08:00
zach
efa69d3668 chore: support for wasmtime 17.0.0 (#665) 2024-01-25 16:11:17 -08:00
zach
fa1beb9155 v1.0.3 2024-01-22 10:21:30 -08:00
Onigbinde Oluwamuyiwa Elijah
fbae853505 fix: make function Plugin::function_extists check the type of the functions. (#664)
This PR addresses #654
It checks the parameters and results of the function as described in the
mentioned issue.
2024-01-22 08:40:09 -08:00
zach
8c8e4a6ffb fix(kernel): fix potential overflow in bounds check when lots of memory has been allocated (#663)
- Fixes potential overflow in bounds checking function
- Found by running the `check_large_allocations` quickcheck test in a
loop
2024-01-19 16:14:36 -08:00
zach
1f1e2699cb v1.0.2 2024-01-19 13:10:13 -08:00
zach
d5dc9b41ab feat: Use quickcheck to test allocations, fix one bug that was uncovered. (#662)
- Adds quickcheck tests for alloc/free/load/store from the kernel, I
wasn't able to include these in the new wasm-bindgen tests because
`getrandom` isn't available on wasm32-unknown-unknown
- Fixes a bug in the calculation of how much memory is needed to
allocate the next block in the kernel. This bug is triggered when
allocating at the end of a page, the size of the MemoryBlock value
wasn't being taken in consideration when determining whether or not to
call memory.grow
2024-01-19 13:04:21 -08:00
zach
822cec4093 v1.0.1 2024-01-18 10:32:04 -08:00
Marton Soos
0b4b732eb8 fix(kernel): Fix calculation of handle offset when splitting re-used memory, add kernel test (#659) 2024-01-17 15:15:51 -08:00
zach
fa368d0b5a feat(convert): add conversions for Option<T> (#658) 2024-01-12 14:45:01 -08:00
Gavin Hayes
092eba5e2f feat: manifest wasm data without base64 (#657)
base64 support is retained. Now `data` can instead be `{"ptr":
ptr_value, "len": len_value}` where `ptr_value` points to a wasm module
and `len_value` is the size of bytes of it.
2024-01-12 16:48:25 -05:00
Benjamin Eckel
94b0b9a430 docs: fix rc version in docs (#656) 2024-01-09 18:56:08 -06:00
Steve Manuel
85cc72e832 docs: add .NET PDK link to table 2024-01-09 07:41:13 -07:00
Steve Manuel
9aee9d8ca5 feat: update README (#655)
Gives the README a bit of a refresh.

---------

Co-authored-by: Benjamin Eckel <bhelx@simst.im>
2024-01-09 07:30:30 -07:00
Gavin Hayes
4012dd22de chore: kernel add Handle and Offset types to differentiate from Pointer (#652)
This cosmetic change to the kernel adds two `u64` types for usage where
`Pointer` was used and it is actually something else or is more
restrictive (a pointer to the start of a data block (handle) or a
relative offset).

Instead of adding `Offset` to match `Length` I'd prefer to use `u64`
directly when referring to those scalars, but not sure if the those
types are preferred?
2024-01-08 12:31:24 -05:00
Steve Manuel
211d55337d feat: add rust-protobuf support to extism-convert (#653)
(code from @zshipko, thank you!)

---------

Co-authored-by: Zach Shipko <zach@dylibso.com>
2024-01-05 16:36:40 -07:00
zach
431bc4d8af cleanup: improve wat detection (again) (#651)
Merged the other one too quickly, this PR is updated with some
additional feedback from @chrisdickinson:

              (Ooh, this could also start with `(;`)
https://github.com/extism/extism/pull/650#discussion_r1443419249

It's also updated to accommodate for modules that start with an open
paren followed by some whitespace. I doubt this covers all of the
permitted syntax but it should be good enough.
2024-01-05 14:58:47 -08:00
zach
cd4fc39655 cleanup: improve wat detection (#650)
- Update to ensure `is_wat` is only true when the input is a valid
string
- Update to allow leading whitespace in a wat file
2024-01-05 14:00:41 -08:00
zach
03e761908c feat: add Plugin::call_get_error_code to get Extism error code along with the error (#649)
- Adds `Plugin::call_get_error_code` to get the Extism error code when a
call fails
2024-01-05 12:52:31 -08:00
zach
26542d5740 feat(kernel): add extism_length_unsafe (#648)
- Adds `length_unsafe` function to the extism kernel, a more performant
`length` for known-valid memory handles

After this is merged I will update go-sdk and js-sdk too.

Closes #643
2024-01-03 09:29:05 -08:00
CosmicHorror
950a0f449f Toggle off default clap feature for cbindgen (#644)
The only feature for `cbindgen` is the `clap` feature for using it as a
standalone binary and isn't needed when using it as a library
2023-12-26 19:40:32 -08:00
zach
c8868c37d8 chore: update wasmtime bounds to include 16.0.0 (#642) 2023-12-20 14:37:43 -08:00
zach
ab812d9281 cleanup: remove default timeout (#641)
The default for `timeout_ms` is currently 30s which was an arbitrary
decision but it forces a user to set `timeout_ms` to null to avoid
having plugins cancelled which is a little strange.
2023-12-18 11:05:12 -08:00
Chris Dickinson
2087398513 v1.0.0-rc7 2023-12-15 15:45:23 -08:00
Chris Dickinson
212e28bec3 fix: give extism_log_drain's param a named type (#638)
This fixes a test failure on the python-sdk [1]. (See also [2]). In
particular, while maturin creates bindings for `extism_log_drain` on
clang platforms, it seems that MSVC cannot generate the required binding
information for `ffi.py`. This results in an `extism_sys` wheel whose
shared object (in this case, a DLL) contains the `extism_log_drain`, but
whose Python FFI bindings don't contain a definition for that function.

Naming the function pointer type parameter resolves the issue. What a
strange issue!

[1]:
https://github.com/extism/python-sdk/actions/runs/7172934060/job/19669775001#step:9:35
[2]:
https://github.com/extism/python-sdk/pull/18#issuecomment-1850892835
2023-12-15 15:40:54 -08:00
zach
fd95729d8d fix(kernel): length function should return 0 for invalid offsets (#635)
Fixes #634 

- Updates `extism_length` to walks the allocation list to determine
valid offsets instead of assuming the provided offset is valid

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: zshipko <zshipko@users.noreply.github.com>
2023-12-14 16:55:13 -08:00
Muhammad Azeez
49e28892bc ci: release extism.dll.lib and extism.dll.a (#633)
Related to #141 and #584 
Follow up of #632
2023-12-13 22:29:29 +03:00
zach
a5edf58747 fix(kernel): improve performance after large allocations, add extism_plugin_reset to give users more control when dealing with large allocations (#627)
See https://github.com/extism/cpp-sdk/issues/15

- Limits a call to memset in the kernel to the size of the current
memory offset instead of the total size of memory.
- Adds `extism_plugin_reset` to the C API and `extism::Plugin::reset` to
Rust

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: zshipko <zshipko@users.noreply.github.com>
2023-12-12 13:56:34 -08:00
zach
e5ffabb975 feat: Add extism_convert::Raw to allow direct encoding using bytemuck (#626)
- Adds `extism_convert::Raw` to encode certain types using their direct
memory representations using https://github.com/Lokathor/bytemuck
- Only enabled on little-endian targets to prevent memory mismatch
issues
- Allows for certain types of structs to be encoded using their
in-memory representation
- Makes passing structs between Rust and C easier since none of the
other encodings are available in C by default.

## Usage
After making a bytemuck-compatible struct:
```rust
use bytemuck::{Zeroable, Pod};

#[derive(Debug, Clone, Copy, PartialEq, Pod, Zeroable)]
#[repr(C)]
struct Point {
  x: i32,
  y: i32,
}
```

It can be used in `call`:

```rust
let input = Point { x: 100, y: 50 };
let Raw(pt): Raw<Point> = plugin.call("transform", Raw(&input))?;
```
2023-12-11 11:14:33 -08:00
Gavin Hayes
0285f64ecf build: add c++ compat to extism.h (#625)
Before `extern "C"` was needed to include the header in C++ code. Now
that's included inside, so it's easier and cleaner to include in c++
projects like the `cpp-sdk`.
2023-12-06 15:34:09 -05:00
Muhammad Azeez
c7a68ed757 ci: bring back nuget packages for Extism runtime (#624)
Seems like these accidentally got removed in #583
2023-12-05 22:32:53 +03:00
zach
9bff8be915 refactor!: better scoping of arguments in host_fn macro, allow visibility in macros to be specified (#621)
Fixes #619  

- Also updates `host_fn`, `encoding`, and `typed_plugin` macros to allow
for visibility specifiers to manage the visibility of the defined types.
This means that `pub` will need to be added to existing invocations that
should remain public
2023-12-05 09:58:35 -08:00
zach
b1cb80fb47 fix: improve handling of 0 length blocks (#622)
Fixes #620 

- Returns `MemoryHandle::null()` instead of returning an error when the
offset is 0
2023-12-04 10:55:26 -08:00
neuronicnobody
03718edbfc fix manifest link (#617)
Fix link to Manifest in the Rust/Runtime README
2023-12-01 17:13:47 -08:00
zach
083b6db029 cleanup: implement Debug and PartialEq for manifest types (#618) 2023-12-01 15:23:01 -08:00
Chris Dickinson
c1b14e841a v1.0.0-rc6 2023-12-01 11:52:18 -08:00
Chris Dickinson
528ae6f6a5 build: combine rust release workflows (#611)
Okay, phew.

The main bug from the [last
PR](https://github.com/extism/extism/pull/610) was that the rust
releases scramble to publish, but we have to publish them in a
particular order for the release to work since they depend on each
other.

There's a secondary bug: `cargo publish` is prone to 502'ing on publish.
I lean towards seeing how painful this is in practice; we should be able
to safely re-run the release flow on failure.
2023-12-01 11:51:18 -08:00
Chris Dickinson
75f2ea2efc doc: add example of linking modules in a plugin (#616)
Add an example of dynamically linking plugins and a benchmark that does
an apples-to-apples comparison of `reflect` using host functions vs.
`reflect` using a linked wasm module. (To my surprise, the host
functions are a _little bit faster_!)
2023-12-01 11:38:27 -08:00
Benjamin Eckel
895f82cf10 docs: Some readme changes on api status (#614)
Just moving this around and changing it up for the beta release.
2023-11-29 14:02:08 -06:00
zach
e4140fda9d cleanup: avoid matching meta.name twice (#613)
As pointed out by @mtb0x1 in
af4fd184e6 (r133737418)
2023-11-28 19:06:58 -08:00
zach
af4fd184e6 cleanup: simplify main module resolution (#612)
This PR simplifies the resolution of the `main` module when multiple
modules are provided. Before we would try to look at the path/URL when
the wasm was coming from disk or via HTTP, now any module missing a name
will be used as `main`. This is much nicer and more consistent since
this is what was being done when no filename was available (i.e. raw
data modules). It also make sense because non-main modules will need to
be named for the functions to be linked correctly.
2023-11-28 16:15:44 -08:00
zach
a517cd23be feat: enable wasmtime caching (#605)
Alternate to: #596 without support for manually compiling/loading native
code

- Enables wasmtime caching: https://docs.wasmtime.dev/cli-cache.html
- Adds `EXTISM_CACHE_CONFIG` and `PluginBuilder::with_cache_config` to
determine where to load a custom cache configuration from
- Adds `PluginBuilder::with_cache_disabled` to disable the cache when
initializing a plugin
  - Setting `EXTISM_CACHE_CONFIG=""` will also disable caching 

## Performance

With caching:
```
create/create_plugin    time:   [2.9079 ms 2.9139 ms 2.9200 ms]                                  
                        change: [+3.2677% +3.6399% +3.9766%] (p = 0.00 < 0.20)
                        Change within noise threshold.
```

Compared to `main`:
```
create/create_plugin    time:   [26.089 ms 26.498 ms 26.923 ms]                                 
                        change: [+0.1729% +2.0868% +4.1337%] (p = 0.04 < 0.20)
                        Change within noise threshold.
```
2023-11-28 11:50:21 -08:00
Chris Dickinson
938e3af7f0 v1.0.0-rc5 2023-11-27 17:30:41 -08:00
Chris Dickinson
06706f07be build: drive cargo releases from git tag (#610)
Follow-up to f7d297f98f.

Update the release workflows for the dependent crates. The Cargo
workflows run on GitHub release publish to match the Python package
release workflow. This means all of our crates are versioned in lockstep
by the Git tag.

There are four changes:

1. Trigger the workflows on GitHub release publish
2. Add the `set version` step from `release.yml` to modify the version
tags in `Cargo.toml`.
3. Publish with `--allow-dirty` (to account for the edit in step 2)
4. In `extism-maturin`, do not inherit `authors` from the workspace
since [PyPI rejects the value we have
set](https://github.com/extism/extism/actions/runs/7012534645/job/19077216730#step:7:23).
2023-11-27 17:28:56 -08:00
Chris Dickinson
e75dd05c6c v1.0.0-rc4 2023-11-27 16:25:46 -08:00
Chris Dickinson
f7d297f98f build: drive crate versions from workspace; drive workspace version from ci (#604)
This is an attempt to sand down [a sharp
edge](https://github.com/extism/extism/actions/runs/6949120346/job/18906546065#step:4:476)
around releases – keeping the `Cargo.toml` versions in-sync with the
release tag, & the versions of the workspace crates aligned with one
another.
2023-11-27 16:14:56 -08:00
zach
a94a0a7a15 cleanup: remove old SDKs (#583)
Removes all SDKs but the Rust SDK/runtime and the C SDK, which is
automatically generated from the Rust crate.

---------

Co-authored-by: Ben <ben@dylibso.com>
Co-authored-by: Steve <steve@dylibso.com>
Co-authored-by: Rob <rob@dylibso.com>
Co-authored-by: Muhammad <muhammad@dylibso.com>
Co-authored-by: Gavin <gavin@dylibso.com>
Co-authored-by: Chris <chris@dylibso.com>
Co-authored-by: Dom <dom@dylibso.com>
Co-authored-by: Charles <charles@dylibso.com>
2023-11-27 11:19:17 -08:00
Chris Dickinson
45b0749fe2 doc: add DEVELOPING.md with release workflow (#602)
Describe the release workflow as flowing from tag -> builds -> release.
2023-11-21 13:30:31 -08:00
Benjamin Eckel
15c30dfa8c fix: forgot to update the runtime version 2023-11-21 14:27:14 -06:00
Benjamin Eckel
7411eef7b0 release: 1.0.0-rc3 (#603) 2023-11-21 13:50:47 -06:00
zach
6e49548ca3 chore: support wasmtime 15 (#601) 2023-11-20 08:36:57 -08:00
George Hopkins
97f4dea8e6 Implement convenience traits for encoded types (#597)
Implement `From<T>` and `Debug` for `Base64<T>`, `Json<T>`, `Msgpack<T>`
and `Protobuf<T>`
2023-11-20 06:34:27 -08:00
George Hopkins
14248f8e17 ci: check formatting of all crates (#598)
Check formatting of all crates to ensure the whole codebase stays
formatted.
2023-11-20 06:34:04 -08:00
Muhammad Azeez
0f3b485813 Update release-dotnet-native.yaml to be resilient against file name changes (#589)
Seems like the assets now include version numbers in their name
2023-11-19 13:50:51 +03:00
Thomas Zahner
ecf5e3b9d4 Fix typo in README.md (#593) 2023-11-17 15:57:16 -08:00
Chris Dickinson
0aadf60272 build(bench): add "consume" and "echo" benchmarks (#595)
Further flesh out our runtime benchmarks: add benchmarks for sending
bytes one-way into Wasm linear memory, as well as testing copy-in then
copy-out. This compliments our `reflect` benchmark; we can get a sense
of how expensive the sub-operations are via `echo` and `consume`.
(Notably, we're missing a `produce` or `emit` that purely generates
output and sends it to the host!)

The source of these plugins is available in `extism/plugins` as
`echo.wat` and `consume.wat` [1].

[1]: https://github.com/extism/plugins/pull/4/files
2023-11-17 15:56:28 -08:00
Chris Dickinson
3eb454dd19 refactor(bench): Add throughput information to reflect function. (#592)
This parameterizes the `reflect` test and calls the `g.throughput` on
each data set to get an idea of our roundtrip throughput. (The changes
follow the "Throughput Measurements" [1] part of the Criterion guide
pretty much to the letter.)

Example output:

```
reflect/reflect 1       time:   [208.57 µs 209.05 µs 209.57 µs]
                        thrpt:  [298.23 MiB/s 298.97 MiB/s 299.66 MiB/s]
```

[1]:
https://bheisler.github.io/criterion.rs/book/user_guide/advanced_configuration.html#throughput-measurements
2023-11-16 17:23:39 -08:00
zach
2a24d13c9b refactor!: use tracing crate for logging, add extism_log_callback function (#578)
- Uses `tracing` instead of `log` crate
- Uses `tracing-subscriber` instead of `fern`
- This allows us to automatically capture `log` events using
`tracing-subscriber`
- Breaking: Makes `extism::set_log_file` private and only used through
the C API, Rust users should use `tracing-subscriber` to determine which
filters/levels to log.
- Adds `extism::set_log_callback` function to set a callback that can be
used for custom logging from Rust.
- Adds `bool extism_log_custom(const char *level)` and
`extism_log_drain(void (*fn)(const char *s, size_t length)` to the C API
to enable custom sinks in other SDKs
2023-11-16 10:35:22 -08:00
Benjamin Eckel
a1cf591de5 release 1.0.0-rc2 (#588) 2023-11-15 16:53:19 -06:00
Rob
d5c6ffb950 chore: loosen dependency requirements for base64 (#576)
Attempts to address an error seen when upgrading both Rust PDK & SDK to
latest:

```
    Updating git repository `https://github.com/extism/extism.git`
    Updating git repository `https://github.com/extism/rust-pdk.git`
    Updating crates.io index
error: failed to select a version for `base64`.
    ... required by package `extism-convert v0.2.0 (https://github.com/extism/extism.git?branch=main#7636c873)`
    ... which satisfies git dependency `extism-convert` of package `extism v1.0.0-alpha.0 (https://github.com/extism/extism.git?branch=main#7636c873)`
    ... which satisfies git dependency `extism` of package `proto_core v0.22.4 (/Users/miles/Projects/proto/crates/core)`
    ... which satisfies path dependency `proto_core` (locked to 0.22.4) of package `proto_cli v0.22.0 (/Users/miles/Projects/proto/crates/cli)`
versions that meet the requirements `^0.21.3` are: 0.21.5, 0.21.4, 0.21.3

all possible versions conflict with previously selected packages.

  previously selected package `base64 v0.21.0`
    ... which satisfies dependency `base64 = "^0.21.0"` (locked to 0.21.0) of package `extism-manifest v0.5.0`
    ... which satisfies dependency `extism-manifest = "^0.5.0"` (locked to 0.5.0) of package `extism-pdk v1.0.0-beta.0 (https://github.com/extism/rust-pdk.git?branch=main#009bf808)`
    ... which satisfies git dependency `extism-pdk` of package `proto_pdk v0.10.2 (/Users/miles/Projects/proto/crates/pdk)`

failed to select a version for `base64` which could resolve this conflict
```
2023-11-15 16:51:16 -06:00
Benjamin Eckel
719462ba61 1.0.0-beta.0 (#587) 2023-11-15 14:47:23 -06:00
Benjamin Eckel
bdb44f2e80 docs: fix readme for runtime rust sdk (#577) 2023-11-13 16:56:02 -06:00
Chris Dickinson
5afa658d10 v1.0.0-rc1 2023-11-13 13:05:56 -08:00
Muhammad Azeez
2fb29025c9 fix: nuget packing in release-dotnet-native.yaml (#524)
Seems like there are some weird subtle differences between Windows and
Linux
2023-11-09 10:00:35 +03:00
zach
91257f0a54 cleanup: simplify logging, include plugin ID in log messages (#573)
My initial goal was to make logging configurable for each plugin instead
of global but wasn't able to accomplish that in this PR (still looking
into it)

- Switches from `log4rs` to `fern` - this significantly simplifies the
logging code
  - Also considered `simplelog`
- Adds `plugin.id` to the logs whenever available
- Uses `extism::plugin::$id` target for functions logged from the PDK
2023-11-08 15:36:47 -08:00
Gavin Hayes
7636c87319 build: libextism/CMakeLists.txt add installing to support in-tree builds that use shared libraries (#575) 2023-11-08 17:17:38 -05:00
Gavin Hayes
6e18283ae6 feat: add add_subdirectory compatible cmake config (#574)
This enables cmake in-tree builds with libextism such as with the
cpp-sdk: https://github.com/extism/cpp-sdk/pull/7
2023-11-08 13:08:35 -05:00
Gavin Hayes
5eb8995347 fix: libextism - make fully static target no longer hardcoded to musl-gcc (#572)
I realized the glibc static build does actually work (though prints
warnings at compile time), so I made it no longer hard-coded to the
compiler. It's still a bad idea, so I added notes for why you shouldn't
do it with glibc.
2023-11-06 19:23:01 -05:00
Gavin Hayes
9992d34510 feat: add x86_64-unknown-linux-musl target, specifying target to make (#571)
The `x86_64-unknown-linux-musl` target does not build dynamic libraries
for now:
```
 warning: dropping unsupported crate type `cdylib` for target `x86_64-unknown-linux-musl`
```

A target may now be optionally specified to the root `Makefile`,
example:
`make RUST_TARGET=x86_64-unknown-linux-musl && sudo make
RUST_TARGET=x86_64-unknown-linux-musl install`

The new musl targets may be used to create entirely static binaries with
libextism. See the new `musl-static` target in `libextism/Makefile`
2023-11-06 17:06:44 -05:00
zach
3226060dd1 refactor!: allow Plugin::new to take raw wasm or Manifest (#569)
- Removes `Plugin::new_with_manifest` and updates `Plugin::new` to take
wasm bytes or `Manifest` using the new `WasmInput` trait
- Removes `PluginBuilder::new_with_module` in favor of a
`PluginBuilder::new` with a `WasmInput` argument
2023-11-06 13:31:24 -08:00
Benjamin Eckel
b0157efca4 chore: fix cargo resolver warning (#570)
```
warning: some crates are on edition 2021 which defaults to `resolver = "2"`, but virtual workspaces default to `resolver = "1"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
```
2023-11-06 14:41:39 -06:00
zach
b86ce1fec7 fix: improve handling of custom error messages (#568)
Fixes #567
2023-11-06 10:18:52 -08:00
zach
94e7722fbc test: add some http tests (#562) 2023-11-06 08:55:10 -08:00
323 changed files with 5496 additions and 32727 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
* @zshipko

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

BIN
.github/assets/logo-horizontal.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

View File

@@ -9,33 +9,8 @@ updates:
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
ignore:
- dependency-name: "wasmtime"
- dependency-name: "wasi-common"
- dependency-name: "wiggle"
- package-ecosystem: "pip"
directory: "python"
schedule:
interval: "weekly"
- package-ecosystem: "mix"
directory: "elixir"
schedule:
interval: "weekly"
- package-ecosystem: "npm"
directory: "node"
schedule:
interval: "weekly"
- package-ecosystem: "composer"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "bundler"
directory: "ruby"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"

View File

@@ -1,28 +0,0 @@
on:
workflow_dispatch:
name: Browser CI
jobs:
node:
name: Browser
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Node env
uses: actions/setup-node@v3
with:
node-version: 18
- name: Test Browser Runtime
run: |
cd browser
npm i
npm run test

View File

@@ -1,31 +0,0 @@
on:
workflow_dispatch:
name: C++ CI
jobs:
cpp:
name: C++
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Install C++ SDK deps
if: ${{ matrix.os == 'macos-latest' }}
run: |
brew install jsoncpp googletest pkg-config
- name: Install C++ SDK deps
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
sudo apt-get install g++ libjsoncpp-dev libgtest-dev pkg-config
- name: Run C++ tests
run: |
cd cpp
LD_LIBRARY_PATH=/usr/local/lib make example
LD_LIBRARY_PATH=/usr/local/lib make test

View File

@@ -1,28 +0,0 @@
on:
workflow_dispatch:
name: D CI
jobs:
d:
name: D
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
# TODO: Use multiple versions once stable
d_version: [ldc-1.33.0]
rust:
- stable
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup D environment
uses: dlang-community/setup-dlang@v1
with:
compiler: ${{ matrix.d_version }}
- name: Test D Host SDK
run: |
dub --version
LD_LIBRARY_PATH=/usr/local/lib dub test

View File

@@ -1,26 +0,0 @@
on:
workflow_dispatch:
name: .NET CI
jobs:
dotnet:
name: .NET
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: 7.x
- name: Test .NET Sdk
run: |
cd dotnet
LD_LIBRARY_PATH=/usr/local/lib dotnet test ./Extism.sln

View File

@@ -1,33 +0,0 @@
on:
workflow_dispatch:
name: Elixir CI
jobs:
elixir:
name: Elixir
runs-on: ${{ matrix.os }}
env:
MIX_ENV: test
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Elixir Host SDK
if: ${{ runner.os != 'macOS' }}
uses: erlef/setup-beam@v1
with:
experimental-otp: true
otp-version: '25.0.4'
elixir-version: '1.14.0'
- name: Test Elixir Host SDK
if: ${{ runner.os != 'macOS' }}
run: |
cd elixir
LD_LIBRARY_PATH=/usr/local/lib mix do deps.get, test

View File

@@ -1,27 +0,0 @@
on:
workflow_dispatch:
name: Go CI
jobs:
go:
name: Go
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Go env
uses: actions/setup-go@v3
- name: Test Go Host SDK
run: |
go version
LD_LIBRARY_PATH=/usr/local/lib go test
cd go
LD_LIBRARY_PATH=/usr/local/lib go run main.go | grep "Hello from Go!"

View File

@@ -1,39 +0,0 @@
on:
workflow_dispatch:
name: Haskell CI
jobs:
haskell:
name: Haskell
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Haskell env
uses: haskell/actions/setup@v2
with:
enable-stack: false
- name: Cache Haskell
id: cache-haskell
uses: actions/cache@v3
with:
path: ./haskell/dist-newstyle
key: ${{ runner.os }}-haskell-${{ hashFiles('haskell/**') }}
- name: Build Haskell Host SDK
if: steps.cache-haskell.outputs.cache-hit != 'true'
run: |
cd haskell
cabal update
LD_LIBRARY_PATH=/usr/local/lib cabal build
- name: Test Haskell SDK
run: |
cd haskell
cabal update
LD_LIBRARY_PATH=/usr/local/lib cabal test

View File

@@ -1,29 +0,0 @@
on:
workflow_dispatch:
name: Java CI
jobs:
java:
name: Java
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
version: [11, 17]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Set up Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '${{ matrix.version }}'
- name: Test Java
run: |
cd java
mvn --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn verify

View File

@@ -1,30 +0,0 @@
on:
workflow_dispatch:
name: Node CI
jobs:
node:
name: Node
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Node env
uses: actions/setup-node@v3
with:
node-version: 18
- name: Test Node Host SDK
run: |
cd node
npm i
LD_LIBRARY_PATH=/usr/local/lib npm run build
LD_LIBRARY_PATH=/usr/local/lib npm run example
LD_LIBRARY_PATH=/usr/local/lib npm run test

View File

@@ -1,40 +0,0 @@
on:
workflow_dispatch:
name: OCaml CI
jobs:
ocaml:
name: OCaml
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup OCaml env
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: ocaml-base-compiler.5.0.0
- name: Cache OCaml
id: cache-ocaml
uses: actions/cache@v3
with:
path: _build
key: ${{ runner.os }}-ocaml-${{ hashFiles('ocaml/**.ml') }}-${{ hashFiles('dune-project') }}
- name: Build OCaml Host SDK
if: steps.cache-ocaml.outputs.cache-hit != 'true'
run: |
opam install -y --deps-only .
cd ocaml
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune build
- name: Test OCaml Host SDK
run: |
opam install -y --deps-only .
cd ocaml
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune exec ./bin/main.exe ../wasm/code.wasm count_vowels -- --input "qwertyuiop"
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune runtest

View File

@@ -1,32 +0,0 @@
on:
workflow_dispatch:
name: PHP CI
jobs:
php:
name: PHP
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup PHP env
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
extensions: ffi
tools: composer
env:
fail-fast: true
- name: Test PHP SDK
run: |
cd php/example
composer install
php index.php

View File

@@ -1,32 +0,0 @@
on:
workflow_dispatch:
name: Python CI
jobs:
python:
name: Python
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Python env
uses: actions/setup-python@v4
with:
python-version: "3.9"
check-latest: true
- name: Install Poetry
uses: snok/install-poetry@v1
- name: Test Python Host SDK
run: |
cd python
cp ../README.md .
poetry install --no-dev
poetry run python example.py
poetry run python -m unittest discover

View File

@@ -1,30 +0,0 @@
on:
workflow_dispatch:
name: Ruby CI
jobs:
ruby:
name: Ruby
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Ruby env
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.0"
- name: Test Ruby Host SDK
run: |
cd ruby
bundle install
ruby example.rb
rake test

View File

@@ -1,119 +0,0 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-rust.yml
- convert/**
- manifest/**
- runtime/**
- rust/**
- libextism/**
workflow_dispatch:
name: Rust CI
env:
RUNTIME_CRATE: extism
LIBEXTISM_CRATE: libextism
jobs:
lib:
name: Extism runtime lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache libextism
id: cache-libextism
uses: actions/cache@v3
with:
path: target/release/libextism.*
key: ${{ runner.os }}-libextism-${{ hashFiles('runtime/**') }}-${{ hashFiles('manifest/**') }}-${{ hashFiles('convert/**') }}
- name: Cache target
id: cache-target
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-target-${{ github.sha }}
- name: Build
if: steps.cache-libextism.outputs.cache-hit != 'true'
shell: bash
run: cargo build --release -p ${{ env.LIBEXTISM_CRATE }}
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: libextism-${{ matrix.os }}
path: |
target/release/libextism.*
lint_and_test:
name: Extism runtime lint and test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache target
id: cache-target
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-target-${{ github.sha }}
- name: Format
run: cargo fmt --check -p ${{ env.RUNTIME_CRATE }}
- name: Lint
run: cargo clippy --release --all-features --no-deps -p ${{ env.RUNTIME_CRATE }}
- name: Test
run: cargo test --release -p ${{ env.RUNTIME_CRATE }}
- name: Test all features
run: cargo test --all-features --release -p ${{ env.RUNTIME_CRATE }}
- name: Test no features
run: cargo test --no-default-features --release -p ${{ env.RUNTIME_CRATE }}
bench:
name: Benchmarking
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache target
id: cache-target
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-target-${{ github.sha }}
- run: cargo install cargo-criterion
- run: cargo criterion

View File

@@ -1,29 +0,0 @@
on:
workflow_dispatch:
name: Zig CI
jobs:
zig:
name: Zig
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
zig_version: ["master"] # eventually use multiple versions once stable
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Zig env
uses: goto-bus-stop/setup-zig@v2
with:
version: ${{ matrix.zig_version }}
- name: Test Zig Host SDK
run: |
zig version
cd zig
LD_LIBRARY_PATH=/usr/local/lib zig build test

View File

@@ -1,25 +1,124 @@
on: [pull_request, workflow_dispatch]
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-rust.yml
- convert/**
- manifest/**
- runtime/**
- rust/**
- libextism/**
workflow_dispatch:
name: CI
name: Rust CI
env:
RUNTIME_CRATE: extism
LIBEXTISM_CRATE: libextism
jobs:
sdk_api_coverage:
name: SDK API Coverage Report
runs-on: ubuntu-latest
lib:
name: Extism runtime lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Setup Python env
uses: actions/setup-python@v4
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
python-version: "3.9"
check-latest: true
- name: Install dependencies
run: |
sudo apt-get install ripgrep
pip3 install pycparser
- name: Run coverage script
id: coverage
run: |
python scripts/sdk_coverage.py
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache libextism
id: cache-libextism
uses: actions/cache@v3
with:
path: target/release/libextism.*
key: ${{ runner.os }}-libextism-${{ hashFiles('runtime/**') }}-${{ hashFiles('manifest/**') }}-${{ hashFiles('convert/**') }}
- name: Cache target
id: cache-target
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-target-${{ github.sha }}
- name: Build
if: steps.cache-libextism.outputs.cache-hit != 'true'
shell: bash
run: cargo build --release -p ${{ env.LIBEXTISM_CRATE }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: libextism-${{ matrix.os }}
path: |
target/release/libextism.*
lint_and_test:
name: Extism runtime lint and test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache target
id: cache-target
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-target-${{ github.sha }}
- name: Format
run: cargo fmt --check
- name: Lint
run: cargo clippy --all --release --all-features --no-deps -- -D "clippy::all"
- name: Test
run: cargo test --release
- name: Test all features
run: cargo test --all-features --release
- name: Test no features
run: cargo test --no-default-features --release
bench:
name: Benchmarking
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache target
id: cache-target
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-target-${{ github.sha }}
- run: cargo install cargo-criterion
- run:
cargo criterion
- run: |
git fetch
git checkout main
cargo criterion

View File

@@ -21,6 +21,9 @@ jobs:
target: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
- name: install wasm-tools
uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Install deps
run: |
sudo apt install wabt --yes
@@ -39,6 +42,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: ${{ env.GIT_EXIT_CODE }} != 0
with:
author: "zshipko <zshipko@users.noreply.github.com>"
title: "update(kernel): extism-runtime.wasm in ${{ github.event.pull_request.head.ref }}"
body: "Automated PR to update `runtime/src/extism-runtime.wasm` in PR #${{ github.event.number }}"
base: "${{ github.event.pull_request.head.ref }}"

View File

@@ -1,26 +0,0 @@
on:
workflow_dispatch:
name: Release extism-convert
jobs:
release-convert:
name: release-extism-convert
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Rust env
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
target: ${{ matrix.target }}
- name: Release Rust Convert Crate
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
run: |
cargo publish --manifest-path convert/Cargo.toml

View File

@@ -1,4 +1,6 @@
on:
release:
types: [published, edited]
workflow_dispatch:
name: Release .NET Native NuGet Packages
@@ -10,37 +12,64 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
fetch-tags: true
with:
fetch-depth: 0
filter: tree:0
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: 7.x
- uses: dawidd6/action-download-artifact@v2
with:
workflow: release.yml
name: release-artifacts
- name: Extract Archive
- name: download release
run: |
mkdir -p dotnet/nuget/runtimes/win-x64/native/
tar -xvzf libextism-x86_64-pc-windows-msvc-main.tar.gz -C dotnet/nuget/runtimes/win-x64/native/
tag='${{ github.ref }}'
tag="${tag/refs\/tags\//}"
gh release download "$tag" -p 'libextism-*.tar.gz'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Archive
run: |
extract_archive() {
# Check if both pattern and destination are provided
if [ -z "$1" ] || [ -z "$2" ]; then
echo "Usage: $0 <filename_pattern> <destination_directory>"
return 1
fi
# Set the filename pattern and destination directory
filename_pattern="$1"
destination_directory="$2"
# Find the archive file with the specified pattern
archive_file=$(ls $filename_pattern 2>/dev/null)
# Check if an archive file is found
if [ -n "$archive_file" ]; then
echo "Found archive file: $archive_file"
# Create the destination directory if it doesn't exist
mkdir -p "$destination_directory"
# Extract the archive to the specified destination
tar -xzvf "$archive_file" -C "$destination_directory"
echo "Extraction complete. Contents placed in: $destination_directory"
else
echo "No matching archive file found with the pattern: $filename_pattern"
fi
}
extract_archive "libextism-x86_64-pc-windows-msvc-*.tar.gz" "nuget/runtimes/win-x64/native/"
extract_archive "libextism-aarch64-apple-darwin-*.tar.gz" "nuget/runtimes/osx-arm64/native/"
extract_archive "libextism-x86_64-apple-darwin-*.tar.gz" "nuget/runtimes/osx-x64/native/"
extract_archive "libextism-x86_64-unknown-linux-gnu-*.tar.gz" "nuget/runtimes/linux-x64/native/"
extract_archive "libextism-aarch64-unknown-linux-gnu-*.tar.gz" "nuget/runtimes/linux-arm64/native/"
extract_archive "libextism-aarch64-unknown-linux-musl-*.tar.gz" "nuget/runtimes/linux-musl-arm64/native/"
mkdir -p dotnet/nuget/runtimes/osx-arm64/native/
tar -xvzf libextism-aarch64-apple-darwin-main.tar.gz -C dotnet/nuget/runtimes/osx-arm64/native/
mkdir -p dotnet/nuget/runtimes/osx-x64/native/
tar -xvzf libextism-x86_64-apple-darwin-main.tar.gz -C dotnet/nuget/runtimes/osx-x64/native/
mkdir -p dotnet/nuget/runtimes/linux-x64/native/
tar -xvzf libextism-x86_64-unknown-linux-gnu-main.tar.gz -C dotnet/nuget/runtimes/linux-x64/native/
mkdir -p dotnet/nuget/runtimes/linux-arm64/native/
tar -xvzf libextism-aarch64-unknown-linux-gnu-main.tar.gz -C dotnet/nuget/runtimes/linux-arm64/native/
mkdir -p dotnet/nuget/runtimes/linux-musl-arm64/native/
tar -xvzf libextism-aarch64-unknown-linux-musl-main.tar.gz -C dotnet/nuget/runtimes/linux-musl-arm64/native/
- name: Pack NuGet packages
run: |
find ./nuget -type f -name "*.csproj" -exec dotnet pack {} -o release-artifacts \;
- name: Publish NuGet packages
run: |
dotnet pack .\dotnet\nuget\Nuget.sln -o release-artifacts
dotnet nuget push --source https://api.nuget.org/v3/index.json ./release-artifacts/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }}
dotnet nuget push --source https://api.nuget.org/v3/index.json ./release-artifacts/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }}

View File

@@ -1,32 +0,0 @@
on:
workflow_dispatch:
name: Release .NET SDK
jobs:
release-sdks:
name: release-dotnet
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install extism shared library
shell: bash
run: |
mkdir -p /home/runner/.local/bin/
export PATH="/home/runner/.local/bin/:$PATH"
curl https://raw.githubusercontent.com/extism/cli/main/install.sh | sh
extism --sudo --prefix /usr/local install
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: 7.x
- name: Test .NET Sdk
run: |
cd dotnet
LD_LIBRARY_PATH=/usr/local/lib dotnet test ./Extism.sln
- name: Publish .NET Sdk
run: |
cd dotnet/src/Extism.Sdk/
dotnet pack -c Release
dotnet nuget push --source https://api.nuget.org/v3/index.json ./bin/Release/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }}

View File

@@ -1,34 +0,0 @@
on:
workflow_dispatch:
name: Release Elixir SDK
jobs:
release-sdks:
name: release-elixir
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install extism shared library
shell: bash
run: |
mkdir -p /home/runner/.local/bin/
export PATH="/home/runner/.local/bin/:$PATH"
curl https://raw.githubusercontent.com/extism/cli/main/install.sh | sh
extism --sudo --prefix /usr/local install
- name: Setup Elixir Host SDK
uses: erlef/setup-beam@v1
with:
experimental-otp: true
otp-version: '25.0.4'
elixir-version: '1.14.0'
- name: Publish Elixir Host SDK to hex.pm
env:
HEX_API_KEY: ${{ secrets.HEX_PM_API_TOKEN }}
run: |
cd elixir
cp ../LICENSE .
make publish

View File

@@ -1,16 +0,0 @@
on:
workflow_dispatch:
name: Release Haskell SDK
jobs:
release-sdks:
name: release-rust
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: cachix/haskell-release-action@v1
with:
- hackage-token: "${{ secrets.HACKAGE_TOKEN }}"
- work-dir: ./haskell

View File

@@ -1,22 +0,0 @@
name: Publish package to the Maven Central Repository
on:
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'adopt'
- name: Publish package
env:
JRELEASER_NEXUS2_USERNAME: ${{ secrets.JRELEASER_NEXUS2_USERNAME }}
JRELEASER_NEXUS2_PASSWORD: ${{ secrets.JRELEASER_NEXUS2_PASSWORD }}
JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }}
JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }}
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.JRELEASER_GPG_PUBLIC_KEY }}
JRELEASER_GITHUB_TOKEN: "dummy"
run: mvn -Prelease clean jreleaser:prepare deploy jreleaser:deploy -DaltDeploymentRepository=local::default::file:./target/staging-deploy

View File

@@ -1,26 +0,0 @@
on:
workflow_dispatch:
name: Release extism-manifest
jobs:
release-manifest:
name: release-extism-manifest
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Rust env
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
target: ${{ matrix.target }}
- name: Release Rust Manifest Crate
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
run: |
cargo publish --manifest-path manifest/Cargo.toml

View File

@@ -1,30 +0,0 @@
on:
workflow_dispatch:
name: Release Node SDK
jobs:
release-sdks:
name: release-node
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node env
uses: actions/setup-node@v3
with:
node-version: 16
registry-url: "https://registry.npmjs.org"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_API_TOKEN }}
CI: true
- name: Release Node Host SDK
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_API_TOKEN }}
CI: true
run: |
cd node
make publish

View File

@@ -1,25 +0,0 @@
on:
workflow_dispatch:
name: Release Ruby SDK
jobs:
release-sdks:
name: release-ruby
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Ruby
uses: actions/setup-ruby@v1
with:
ruby-version: '3.1' # Version range or exact version of a Ruby version to use, using semvers version range syntax.
- name: Publish Ruby Gem
env:
RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_TOKEN }}
run: |
cd ruby
make publish RUBYGEMS_API_KEY=$RUBYGEMS_API_KEY

View File

@@ -1,4 +1,6 @@
on:
release:
types: [published, edited]
workflow_dispatch:
name: Release Runtime/Rust SDK
@@ -10,6 +12,21 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: '${{ github.ref }}'
- name: Set version
shell: bash
run: |
version="${{ github.ref }}"
if [[ "$version" = "refs/heads/main" ]]; then
version="0.0.0-dev"
else
version="${version/refs\/tags\/v/}"
fi
sed -i -e "s/0.0.0+replaced-by-ci/${version}/g" Cargo.toml
pyproject="$(cat extism-maturin/pyproject.toml)"
<<<"$pyproject" >extism-maturin/pyproject.toml sed -e 's/^version = "0.0.0.replaced-by-ci"/version = "'"$version"'"/g'
- name: Setup Rust env
uses: actions-rs/toolchain@v1
@@ -19,8 +36,50 @@ jobs:
override: true
target: ${{ matrix.target }}
- name: Release Rust convert-macros Crate
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
run: |
version=$(cargo metadata --format-version=1 | jq -r '.packages[] | select(.name == "extism") | .version')
if ! &>/dev/null curl -sLIf https://crates.io/api/v1/crates/extism-convert-macros/${version}/download; then
cargo publish --manifest-path convert-macros/Cargo.toml --allow-dirty
else
echo "already published ${version}"
fi
- name: Release Rust Convert Crate
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
run: |
version=$(cargo metadata --format-version=1 | jq -r '.packages[] | select(.name == "extism") | .version')
if ! &>/dev/null curl -sLIf https://crates.io/api/v1/crates/extism-convert/${version}/download; then
cargo publish --manifest-path convert/Cargo.toml --allow-dirty
else
echo "already published ${version}"
fi
- name: Release Rust Manifest Crate
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
run: |
version=$(cargo metadata --format-version=1 | jq -r '.packages[] | select(.name == "extism") | .version')
if ! &>/dev/null curl -sLIf https://crates.io/api/v1/crates/extism-manifest/${version}/download; then
cargo publish --manifest-path manifest/Cargo.toml --allow-dirty
else
echo "already published ${version}"
fi
- name: Release Runtime
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
run: |
cargo publish --manifest-path runtime/Cargo.toml
version=$(cargo metadata --format-version=1 | jq -r '.packages[] | select(.name == "extism") | .version')
if ! &>/dev/null curl -sLIf https://crates.io/api/v1/crates/extism/${version}/download; then
cargo publish --manifest-path runtime/Cargo.toml --allow-dirty
else
echo "already published ${version}"
fi

View File

@@ -1,17 +1,12 @@
on:
workflow_dispatch:
push:
branches: [ main ]
branches: [ main, "v*" ]
tags:
- 'v*'
name: Release
env:
RUNTIME_MANIFEST: runtime/Cargo.toml
RUNTIME_CRATE: libextism
RUSTFLAGS: -C target-feature=-crt-static
ARTIFACT_DIR: release-artifacts
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -21,6 +16,11 @@ jobs:
release:
name: ${{ matrix.os }} ${{ matrix.target }}
runs-on: ${{ matrix.os }}-latest
env:
RUNTIME_MANIFEST: runtime/Cargo.toml
RUNTIME_CRATE: libextism
RUSTFLAGS: -C target-feature=-crt-static
ARTIFACT_DIR: release-artifacts-${{ matrix.os }}-${{ matrix.target }}
strategy:
matrix:
include:
@@ -28,42 +28,56 @@ jobs:
target: 'x86_64-apple-darwin'
artifact: 'libextism.dylib'
static-artifact: 'libextism.a'
static-dll-artifact: ''
pc-in: 'extism.pc.in'
static-pc-in: 'extism-static.pc.in'
- os: 'macos'
target: 'aarch64-apple-darwin'
artifact: 'libextism.dylib'
static-artifact: 'libextism.a'
static-dll-artifact: ''
pc-in: 'extism.pc.in'
static-pc-in: 'extism-static.pc.in'
- os: 'ubuntu'
target: 'aarch64-unknown-linux-gnu'
artifact: 'libextism.so'
static-artifact: 'libextism.a'
static-dll-artifact: ''
pc-in: 'extism.pc.in'
static-pc-in: 'extism-static.pc.in'
- os: 'ubuntu'
target: 'aarch64-unknown-linux-musl'
artifact: 'libextism.so'
static-artifact: 'libextism.a'
static-dll-artifact: ''
pc-in: 'extism.pc.in'
static-pc-in: 'extism-static.pc.in'
- os: 'ubuntu'
target: 'x86_64-unknown-linux-gnu'
artifact: 'libextism.so'
static-artifact: 'libextism.a'
static-dll-artifact: ''
pc-in: 'extism.pc.in'
static-pc-in: 'extism-static.pc.in'
- os: 'ubuntu'
target: 'x86_64-unknown-linux-musl'
artifact: 'libextism.so'
static-artifact: 'libextism.a'
static-dll-artifact: ''
pc-in: 'extism.pc.in'
static-pc-in: 'extism-static.pc.in'
- os: 'windows'
target: 'x86_64-pc-windows-gnu'
artifact: 'extism.dll'
static-artifact: 'libextism.a'
static-dll-artifact: 'libextism.dll.a'
pc-in: 'extism.pc.in'
static-pc-in: 'extism-static.pc.in'
- os: 'windows'
target: 'x86_64-pc-windows-msvc'
artifact: 'extism.dll'
static-artifact: 'extism.lib'
static-dll-artifact: 'extism.dll.lib'
pc-in: ''
static-pc-in: ''
@@ -71,13 +85,24 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
- name: Set version
shell: bash
run: |
version="${{ github.ref }}"
if [[ "$version" = "refs/heads/main" ]]; then
version="0.0.0-dev"
else
version="${version/refs\/tags\/v/}"
fi
sed -i -e "s/0.0.0+replaced-by-ci/${version}/g" Cargo.toml
pyproject="$(cat extism-maturin/pyproject.toml)"
<<<"$pyproject" >extism-maturin/pyproject.toml sed -e 's/^version = "0.0.0.replaced-by-ci"/version = "'"$version"'"/g'
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
target: ${{ matrix.target }}
override: true
toolchain: stable
- uses: Swatinem/rust-cache@v2
with:
@@ -86,24 +111,15 @@ jobs:
cache-on-failure: "true"
- name: Build Target (${{ matrix.os }} ${{ matrix.target }})
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.os != 'windows' }}
command: build
args: --release --target ${{ matrix.target }} -p ${{ env.RUNTIME_CRATE }}
- name: set extism-maturin version
shell: bash
if: ${{ matrix.os != 'windows' }}
run: |
pyproject="$(cat extism-maturin/pyproject.toml)"
version="${{ github.ref }}"
if [[ "$version" = "refs/heads/main" ]]; then
version="0.0.0-dev"
else
version="${version/refs\/tags\/v/}"
fi
cargo install cross
cross build --release --target ${{ matrix.target }} -p ${{ env.RUNTIME_CRATE }}
<<<"$pyproject" >extism-maturin/pyproject.toml sed -e 's/^version = "0.0.0.replaced-by-ci"/version = "'"$version"'"/g'
- name: Build Target (${{ matrix.os }} ${{ matrix.target }})
if: ${{ matrix.os == 'windows' }}
run: |
cargo build --release --target ${{ matrix.target }} -p ${{ env.RUNTIME_CRATE }}
- uses: actions/setup-python@v4
with:
@@ -152,7 +168,8 @@ jobs:
cp LICENSE ${SRC_DIR}
tar -C ${SRC_DIR} -czvf ${ARCHIVE} extism.h \
${{ matrix.artifact }} ${{ matrix.static-artifact }} \
${{ matrix.pc-in }} ${{ matrix.static-pc-in }}
${{ matrix.pc-in }} ${{ matrix.static-pc-in }} \
${{ matrix.static-dll-artifact }}
ls -ll ${ARCHIVE}
if &>/dev/null which shasum; then
@@ -175,7 +192,7 @@ jobs:
ls -ll ${DEST_DIR}
- name: Upload Artifact to Summary
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ env.ARTIFACT_DIR }}
path: ${{ env.ARTIFACT_DIR }}
@@ -194,9 +211,10 @@ jobs:
needs: [release]
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: ${{ env.ARTIFACT_DIR }}
pattern: release-artifacts-*
merge-multiple: true
- uses: "marvinpinto/action-automatic-releases@latest"
with:

4
.gitignore vendored
View File

@@ -46,4 +46,6 @@ java/.DS_Store
extism-maturin/src/extism.h
runtime/*.log
libextism/example
libextism/extism*.pc
libextism/extism*.pc
*.cwasm
test-cache

View File

@@ -1 +0,0 @@
version = 0.26.0

View File

@@ -1,9 +1,18 @@
[workspace]
members = [
"extism-maturin",
"manifest",
"runtime",
"libextism",
"convert"
]
resolver = "2"
members = ["extism-maturin", "manifest", "runtime", "libextism", "convert", "convert-macros"]
exclude = ["kernel"]
[workspace.package]
edition = "2021"
authors = ["The Extism Authors", "oss@extism.org"]
license = "BSD-3-Clause"
homepage = "https://extism.org"
repository = "https://github.com/extism/extism"
version = "0.0.0+replaced-by-ci"
[workspace.dependencies]
extism = { path = "./runtime", version = "0.0.0+replaced-by-ci" }
extism-convert = { path = "./convert", version = "0.0.0+replaced-by-ci" }
extism-convert-macros = { path = "./convert-macros", version = "0.0.0+replaced-by-ci" }
extism-manifest = { path = "./manifest", version = "0.0.0+replaced-by-ci" }

117
DEVELOPING.md Normal file
View File

@@ -0,0 +1,117 @@
# HACKING
## cutting releases
### goals
Cutting a release should be a boring, rote process with as little excitement as
possible. Following the processes in this document, we should be able to cut a
release at any time without worrying about producing bad artifacts. Our process
should let us resolve build issues without affecting library users.
### branching
1. The `main` branch represents the next major version of the library.
2. Previous major versions should be tracked using `v0.x`, `v1.x`, `v2.x`, used
for backporting changes as necessary.
3. Libraries should generate a `latest` release using, e.g.,
`marvinpinto/action-automatic-releases` on changes to the `main` branch.
### tag and release process
1. Pick a target semver value. Prepend the semver value with `v`: `v1.2.3`.
Increment the minor version for additive changes and patch for bugfixes.
- For trickier changes, consider using release candidates: `rc0`, `rc1`, etc.
2. Create an empty git commit for the tag to point at: `git commit -m 'v1.2.3-rc1' --allow-empty`.
3. Create a new tag against that commit: `v1.2.3-rc1`.
4. Push the changes to the library: `git push origin main v1.2.3-rc1`.
- You can separate these steps: `git push origin main` followed by `git push origin v1.2.3-rc1`,
if you want to make absolutely sure the commit you're pushing builds correctly before tagging it.
5. Wait for the tag `build` workflow to complete.
- The `build` workflow should create a _draft_ release (using `softprops/action-gh-release` with `draft`
set to `true`) and upload built artifacts to the release.
6. Once the workflow is complete, do whatever testing is necessary using the artifacts.
- TODO: We can add automation to this step so that we test on downstream deps automatically: e.g., if we
build a new kernel, we _should_ be able to trigger tests in the `python-sdk` _using_ that new kernel.
7. Once we're confident the release is good, go to the releases page for the library and edit the draft release.
- If the release is a release candidate (`rc0..N`), make sure to mark the release as a "prerelease".
- Publish the draft release.
- This kicks off the publication workflow: taking the artifacts built during the `build` workflow and publishing
them to any necessary registry or repository.
- In extism, this publishes `extism-maturin` to PyPI as `extism-sys` and the dotnet packages to nuget.
- In `python-sdk`, this publishes `extism` to PyPI.
- In `js-sdk`, this publishes `@extism/extism` (and `extism`) to NPM.
> **Note**
> If you're at all worried about a release, use a private fork of the target library repo to test the release first (e.g., `extism/dev-extism`.)
#### CLI flow
For official releases:
```
$ git commit -m 'v9.9.9' --allow-empty
$ git tag v9.9.9
$ git push origin main v9.9.9
$ gh run watch
$ gh release edit v9.9.9 --tag v9.9.9 --title 'v9.9.9' --draft=false
$ gh run watch
```
For prereleases:
```
$ git commit -m 'v9.9.9' --allow-empty
$ git tag v9.9.9
$ git push origin main v9.9.9
$ gh run watch
$ gh release edit v9.9.9 --tag v9.9.9 --title 'v9.9.9' --draft=false --prerelease
$ gh run watch
```
### implementation
Libraries should:
- Provide a `ci` workflow, triggered on PR and `workflow_dispatch`.
- This workflow should exercise the tests, linting, and documentation generation of the library.
- Provide a `build` workflow, triggered on `v*` tags and merges to `main`
- This workflow should produce artifacts and attach them to a draft release (if operating on a tag) or a `latest` release (if operating on `main`.)
- Artifacts include: source tarballs, checksums, shared objects, and documentation.
- Provide a `release` workflow, triggered on github releases:
- This workflow should expect artifacts from the draft release to be available.
- Artifacts from the release should be published to their final destination as part of this workflow: tarballs to NPM, documentation to Cloudflare R2/Amazon S3/$yourFavoriteBucket.
### A rough list of libraries and downstreams
```mermaid
flowchart TD;
A["runtime"] --> B["libextism"];
B --> C["extism-maturin"];
B --> X["nuget-extism"];
C --> D["python-sdk"];
B --> E["ruby-sdk"];
A --> F["go-sdk"];
G["plugins"] --> B;
G --> D;
G --> E;
G --> F;
G --> H["js-sdk"];
F --> I["cli"];
G --> J["dotnet-sdk"];
X --> J;
G --> K["cpp-sdk"];
G --> L["zig-sdk"];
B --> L;
G --> M["haskell-sdk"];
B --> M;
G --> N["php-sdk"];
B --> N;
G --> O["elixir-sdk"];
B --> O;
G --> P["d-sdk"];
B --> P;
G --> Q["ocaml-sdk"];
B --> Q;
```

View File

@@ -3,10 +3,13 @@ SOEXT=so
AEXT=a
FEATURES?=default
DEFAULT_FEATURES?=yes
RUST_TARGET?=
EXTRA_LIBS=
UNAME := $(shell uname -s)
ifeq ($(UNAME),Darwin)
SOEXT=dylib
EXTRA_LIBS=-framework Security
endif
ifeq ($(DEFAULT_FEATURES),no)
@@ -19,29 +22,39 @@ else
FEATURE_FLAGS=--features $(FEATURES)
endif
ifeq ($(RUST_TARGET),)
TARGET_FLAGS=
else
TARGET_FLAGS=--target $(RUST_TARGET)
endif
build:
cargo build --release $(FEATURE_FLAGS) --manifest-path libextism/Cargo.toml
sed -e "s%PREFIX%$(DEST)%" libextism/extism.pc.in > libextism/extism.pc
sed -e "s%PREFIX%$(DEST)%" libextism/extism-static.pc.in > libextism/extism-static.pc
cargo build --release $(FEATURE_FLAGS) --manifest-path libextism/Cargo.toml $(TARGET_FLAGS)
sed -e "s%@CMAKE_INSTALL_PREFIX@%$(DEST)%" libextism/extism.pc.in > libextism/extism.pc
sed -e "s%@CMAKE_INSTALL_PREFIX@%$(DEST)%" \
-e "s%Libs: %Libs: $(EXTRA_LIBS) %" libextism/extism-static.pc.in > libextism/extism-static.pc
bench:
@(cargo criterion || echo 'For nicer output use cargo-criterion: `cargo install cargo-criterion` - using `cargo bench`') && cargo bench
@(cargo criterion $(TARGET_FLAGS) || echo 'For nicer output use cargo-criterion: `cargo install cargo-criterion` - using `cargo bench`') && cargo bench $(TARGET_FLAGS)
.PHONY: kernel
kernel:
cd kernel && bash build.sh
lint:
cargo clippy --release --no-deps --manifest-path runtime/Cargo.toml
cargo clippy --release --no-deps --manifest-path runtime/Cargo.toml $(TARGET_FLAGS)
debug:
RUSTFLAGS=-g $(MAKE) build
RUSTFLAGS=-g RUST_TARGET=$(RUST_TARGET) $(MAKE) build
install:
echo $(RUST_TARGET)
mkdir -p $(DEST)/lib $(DEST)/include $(DEST)/lib/pkgconfig
install runtime/extism.h $(DEST)/include/extism.h
install target/release/libextism.$(SOEXT) $(DEST)/lib/libextism.$(SOEXT)
install target/release/libextism.$(AEXT) $(DEST)/lib/libextism.$(AEXT)
if [ -f target/$(RUST_TARGET)/release/libextism.$(SOEXT) ]; then \
install target/$(RUST_TARGET)/release/libextism.$(SOEXT) $(DEST)/lib/libextism.$(SOEXT); \
fi
install target/$(RUST_TARGET)/release/libextism.$(AEXT) $(DEST)/lib/libextism.$(AEXT)
install libextism/extism.pc $(DEST)/lib/pkgconfig/extism.pc
install libextism/extism-static.pc $(DEST)/lib/pkgconfig/extism-static.pc

204
README.md
View File

@@ -1,62 +1,188 @@
### _Welcome!_
<div align="center">
<a href="https://extism.org">
<picture>
<source media="(prefers-color-scheme: dark)" srcset=".github/assets/logo-horizontal-darkmode.png">
<img alt="Extism - the WebAssembly framework" width="75%" style="max-width: 600px" src=".github/assets/logo-horizontal.png">
</picture>
</a>
**Please note:** This project still under active development and APIs are changing as we hit 1.0. Currently, the main branch has many breaking changes. Our current release is 0.5.x. Until we release 1.0, we are cutting these releases from the [stable](https://github.com/extism/extism/tree/stable) branch.
[![Discord](https://img.shields.io/discord/1011124058408112148?color=%23404eed&label=Community%20Chat&logo=Discord&logoColor=%23404eed)](https://extism.org/discord)
![GitHub Org's stars](https://img.shields.io/github/stars/extism)
![Downloads](https://img.shields.io/crates/d/extism-manifest)
![GitHub License](https://img.shields.io/github/license/extism/extism)
![GitHub release (with filter)](https://img.shields.io/github/v/release/extism/extism)
If you're interested in working on or building with Extism, please join our [Discord](https://discord.gg/cx3usBCWnc) and let us know - we are happy to help get you started.
</div>
[![Discord](https://img.shields.io/discord/1011124058408112148?color=%23404eed&label=Community%20Chat&logo=Discord&logoColor=%23404eed)](https://discord.gg/cx3usBCWnc)
# Overview
# [Extism](https://extism.org)
Extism is a lightweight framework for building with WebAssembly (Wasm). It
supports running Wasm code on servers, the edge, CLIs, IoT, browsers and
everything in between. Extism is designed to be "universal" in that it supports
a common interface, no matter where it runs.
The universal plug-in system. Run WebAssembly extensions inside your app. Use idiomatic Host SDKs for [Go](https://github.com/extism/go-sdk#readme),
[Ruby](https://github.com/extism/ruby-sdk#readme),
[Python](https://github.com/extism/python-sdk#readme),
[JavaScript](https://github.com/extism/js-sdk#readme),
[Rust](/runtime/#readme),
[C](libextism/#readme),
[C++](https://github.com/extism/cpp-sdk/#readme),
[OCaml](https://github.com/extism/ocaml-sdk#readme),
[Haskell](https://github.com/extism/haskell-sdk#readme),
[PHP](https://github.com/extism/php-sdk#readme),
[Elixir](https://github.com/extism/elixir-sdk#readme),
[.NET](https://github.com/extism/dotnet-sdk#readme),
[Java](https://github.com/extism/java-sdk#readme),
[Zig](https://github.com/extism/zig-sdk#readme),
[D](https://github.com/extism/d-sdk#readme),
&amp; more (others coming soon).
> **Note:** One of the primary use cases for Extism is **building extensible
> software & plugins**. You want to be able to execute arbitrary, untrusted code
> from your users? Extism makes this safe and practical to do.
Plug-in development kits (PDK) for plug-in authors supported in [Rust](https://github.com/extism/rust-pdk#readme), [AssemblyScript](https://github.com/extism/assemblyscript-pdk#readme), [Go](https://github.com/extism/go-pdk#readme), [C/C++](https://github.com/extism/c-pdk#readme), [Haskell](https://github.com/extism/haskell-pdk#readme), [JavaScript](https://github.com/extism/js-pdk#readme), [C#](https://github.com/extism/dotnet-pdk#readme), [F#](https://github.com/extism/dotnet-pdk#readme) and [Zig](https://github.com/extism/zig-pdk#readme).
Additionally, Extism adds some extra utilities on top of standard Wasm runtimes.
For example, we support persistent memory/module-scope variables, secure &
host-controlled HTTP without WASI, runtime limiters & timers, simpler host
function linking, and more. Extism users build:
<p align="center">
<img style="width: 70%;" src="https://user-images.githubusercontent.com/7517515/210286900-39b144fd-1b26-4dd0-b7a9-2b5755bc174d.png" alt="Extism embedded SDK language support"/>
</p>
- plug-in systems
- FaaS platforms
- code generators
- web applications
- & much more...
# Supported Targets
Add a flexible, secure, and _bLaZiNg FaSt_ plug-in system to your project. Server, desktop, mobile, web, database -- you name it. Enable users to write and execute safe extensions to your software in **3 easy steps:**
We currently provide releases for the following targets:
### 1. Import
- aarch64-apple-darwin
- aarch64-unknown-linux-gnu
- aarch64-unknown-linux-musl
- x86_64-apple-darwin
- x86_64-pc-windows-gnu
- x86_64-pc-windows-msvc
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
Import an Extism Host SDK into your code as a library dependency.
For Android we suggest taking a look at the [Chicory SDK](https://github.com/extism/chicory-sdk) for a pure Java
Extism runtime.
### 2. Integrate
# Run WebAssembly In Your App
Identify the place(s) in your code where some arbitrary logic should run (the plug-in!), returning your code some results.
Pick a SDK to import into your program, and refer to the documentation to get
started:
### 3. Execute
| Type | Language | Source Code | Package |
| ----------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| Rust SDK | <img alt="Rust SDK" src="https://extism.org/img/sdk-languages/rust.svg" width="50px"/> | https://github.com/extism/extism/tree/main/runtime | [Crates.io](https://crates.io/crates/extism) |
| JS SDK | <img alt="JS SDK" src="https://extism.org/img/sdk-languages/js.svg" width="50px"/> | https://github.com/extism/js-sdk <br/>(supports Web, Node, Deno & Bun!) | [NPM](https://www.npmjs.com/package/@extism/extism) |
| Elixir SDK | <img alt="Elixir SDK" src="https://extism.org/img/sdk-languages/elixir.svg" width="50px"/> | https://github.com/extism/elixir-sdk | [Hex](https://hex.pm/packages/extism) |
| Go SDK | <img alt="Go SDK" src="https://extism.org/img/sdk-languages/go.svg" width="50px"/> | https://github.com/extism/go-sdk | [Go mod](https://pkg.go.dev/github.com/extism/go-sdk) |
| Haskell SDK | <img alt="Haskell SDK" src="https://extism.org/img/sdk-languages/haskell.svg" width="50px"/> | https://github.com/extism/haskell-sdk | [Hackage](https://hackage.haskell.org/package/extism) |
| Java SDK | <img alt="Java SDK" src="https://extism.org/img/sdk-languages/java-android.svg" width="50px"/> | https://github.com/extism/java-sdk | [Sonatype](https://central.sonatype.com/artifact/org.extism.sdk/extism) |
| .NET SDK | <img alt=".NET SDK" src="https://extism.org/img/sdk-languages/dotnet.svg" width="50px"/> | https://github.com/extism/dotnet-sdk <br/>(supports C# & F#!) | [Nuget](https://www.nuget.org/packages/Extism.Sdk) |
| OCaml SDK | <img alt="OCaml SDK" src="https://extism.org/img/sdk-languages/ocaml.svg" width="50px"/> | https://github.com/extism/ocaml-sdk | [opam](https://opam.ocaml.org/packages/extism/) |
| Perl SDK | <img alt="Perl SDK" src="https://extism.org/img/sdk-languages/perl.svg" width="50px"/> | https://github.com/extism/perl-sdk | [CPAN](https://metacpan.org/pod/Extism) |
| PHP SDK | <img alt="PHP SDK" src="https://extism.org/img/sdk-languages/php.svg" width="50px"/> | https://github.com/extism/php-sdk | [Packagist](https://packagist.org/packages/extism/extism) |
| Python SDK | <img alt="Python SDK" src="https://extism.org/img/sdk-languages/python.svg" width="50px"/> | https://github.com/extism/python-sdk | [PyPi](https://pypi.org/project/extism/) |
| Ruby SDK | <img alt="Ruby SDK" src="https://extism.org/img/sdk-languages/ruby.svg" width="50px"/> | https://github.com/extism/ruby-sdk | [RubyGems](https://rubygems.org/gems/extism) |
| Zig SDK | <img alt="Zig SDK" src="https://extism.org/img/sdk-languages/zig.svg" width="50px"/> | https://github.com/extism/zig-sdk | N/A |
| C SDK | <img alt="C SDK" src="https://extism.org/img/sdk-languages/c.svg" width="50px"/> | https://github.com/extism/extism/tree/main/libextism | N/A |
| C++ SDK | <img alt="C++ SDK" src="https://extism.org/img/sdk-languages/cpp.svg" width="50px"/> | https://github.com/extism/cpp-sdk | N/A |
Load WebAssembly modules at any time in your app's lifetime and Extism will execute them in a secure sandbox, fully isolated from your program's memory.
# Compile WebAssembly to run in Extism Hosts
---
Extism Hosts (running the SDK) must execute WebAssembly code that has a
[PDK, or Plug-in Development Kit](https://extism.org/docs/concepts/pdk), library
compiled in to the `.wasm` binary. PDKs make it easy for plug-in / extension
code authors to read input from the host and return data back, read provided
configuration, set/get variables, make outbound HTTP calls if allowed, and more.
Pick a PDK to import into your Wasm program, and refer to the documentation to
get started:
| Type | Language | Source Code | Package |
| ------------------ | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | --------------------------------------------------------- |
| Rust PDK | <img alt="Rust PDK" src="https://extism.org/img/sdk-languages/rust.svg" width="50px"/> | https://github.com/extism/rust-pdk | [Crates.io](https://crates.io/crates/extism-pdk) |
| JS PDK | <img alt="JS PDK" src="https://extism.org/img/sdk-languages/js.svg" width="50px"/> | https://github.com/extism/js-pdk | N/A |
| Python PDK | <img alt="Python PDK" src="https://extism.org/img/sdk-languages/python.svg" width="50px"/> | https://github.com/extism/python-pdk | N/A |
| Go PDK | <img alt="Go PDK" src="https://extism.org/img/sdk-languages/go.svg" width="50px"/> | https://github.com/extism/go-pdk | [Go mod](https://pkg.go.dev/github.com/extism/go-pdk) |
| Haskell PDK | <img alt="Haskell PDK" src="https://extism.org/img/sdk-languages/haskell.svg" width="50px"/> | https://github.com/extism/haskell-pdk | [Hackage](https://hackage.haskell.org/package/extism-pdk) |
| AssemblyScript PDK | <img alt="AssemblyScript PDK" src="https://extism.org/img/sdk-languages/assemblyscript.svg" width="50px"/> | https://github.com/extism/assemblyscript-pdk | [NPM](https://www.npmjs.com/package/@extism/as-pdk) |
| .NET PDK | <img alt=".NET PDK" src="https://extism.org/img/sdk-languages/dotnet.svg" width="50px"/> | https://github.com/extism/dotnet-pdk <br/>(supports C# & F#!) | [Nuget](https://www.nuget.org/packages/Extism.Pdk) |
| C PDK | <img alt="C PDK" src="https://extism.org/img/sdk-languages/c.svg" width="50px"/> | https://github.com/extism/c-pdk | N/A |
| C++ PDK | <img alt="C++ PDK" src="https://extism.org/img/sdk-languages/cpp.svg" width="50px"/> | https://github.com/extism/cpp-pdk | N/A |
| Zig PDK | <img alt="Zig PDK" src="https://extism.org/img/sdk-languages/zig.svg" width="50px"/> | https://github.com/extism/zig-pdk | N/A |
# Generating Bindings
It's often very useful to define a schema to describe the function signatures
and types you want to use between Extism SDK and PDK languages.
[XTP Bindgen](https://github.com/dylibso/xtp-bindgen) is an open source
framework to generate PDK bindings for Extism plug-ins. It's used by the
[XTP Platform](https://www.getxtp.com/), but can be used outside of the platform
to define any Extism compatible plug-in system.
## 1. Install the `xtp` CLI.
See installation instructions
[here](https://docs.xtp.dylibso.com/docs/cli#installation).
## 2. Create a schema using our OpenAPI-inspired IDL:
```yaml
version: v1-draft
exports:
CountVowels:
input:
type: string
contentType: text/plain; charset=utf-8
output:
$ref: "#/components/schemas/VowelReport"
contentType: application/json
# components.schemas defined in example-schema.yaml...
```
> See an example in [example-schema.yaml](./example-schema.yaml), or a full
> "kitchen sink" example on
> [the docs page](https://docs.xtp.dylibso.com/docs/concepts/xtp-schema/).
## 3. Generate bindings to use from your plugins:
```
xtp plugin init --schema-file ./example-schema.yaml
> 1. TypeScript
2. Go
3. Rust
4. Python
5. C#
6. Zig
7. C++
8. GitHub Template
9. Local Template
```
This will create an entire boilerplate plugin project for you to get started
with. Implement the empty function(s), and run `xtp plugin build` to compile
your plugin.
> For more information about XTP Bindgen, see the
> [dylibso/xtp-bindgen](https://github.com/dylibso/xtp-bindgen) repository and
> the official
> [XTP Schema documentation](https://docs.xtp.dylibso.com/docs/concepts/xtp-schema).
# Support
## Discord
If you experience any problems or have any questions, please join our
[Discord](https://extism.org/discord) and let us know. Our community is very
responsive and happy to help get you started.
## Usage
Head to the [project website](https://extism.org) for more information and docs. Also, consider reading an [overview](https://extism.org/docs/overview) of Extism and its goals & approach.
Head to the [project website](https://extism.org) for more information and docs.
Also, consider reading an [overview](https://extism.org/docs/overview) of Extism
and its goals & approach.
## Contribution
Thank you for considering a contribution to Extism, we are happy to help you make a PR or find something to work on!
Thank you for considering a contribution to Extism, we are happy to help you
make a PR or find something to work on!
The easiest way to start would be to join the [Discord](https://discord.gg/cx3usBCWnc) or open an issue on the [`extism/proposals`](https://github.com/extism/proposals) issue tracker, which can eventually become an Extism Improvement Proposal (EIP).
The easiest way to start would be to join the
[Discord](https://extism.org/discord) or open an issue on the
[`extism/proposals`](https://github.com/extism/proposals) issue tracker, which
can eventually become an Extism Improvement Proposal (EIP).
For more information, please read the
[Contributing](https://extism.org/docs/concepts/contributing) guide.
---
@@ -65,8 +191,8 @@ The easiest way to start would be to join the [Discord](https://discord.gg/cx3us
Extism is an open-source product from the team at:
<p align="left">
<a href="https://dylib.so" _target="blanks"><img width="200px" src="https://user-images.githubusercontent.com/7517515/198204119-5afdebb9-a5d8-4322-bd2a-46179c8d7b24.svg"/></a>
<a href="https://dylibso.com" _target="blanks"><img width="200px" src="https://user-images.githubusercontent.com/7517515/198204119-5afdebb9-a5d8-4322-bd2a-46179c8d7b24.svg"/></a>
</p>
_Reach out and tell us what you're building! We'd love to help._
_Reach out and tell us what you're building! We'd love to help:_
<a href="mailto:hello@dylibso.com">hello@dylibso.com</a>

130
browser/.gitignore vendored
View File

@@ -1,130 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

View File

@@ -1,5 +0,0 @@
{
"printWidth": 120,
"trailingComma": "all",
"singleQuote": true
}

View File

@@ -1,28 +0,0 @@
.PHONY: test
prepare:
npm install
build:
npm run build
test: prepare
npm run test
clean:
echo "No clean implemented"
publish: clean prepare build
npm publish
format:
npx prettier --write src
lint:
npx prettier --check src
docs:
npx typedoc --out doc src
show-docs: docs
open doc/index.html

View File

@@ -1,4 +0,0 @@
# Browser Host SDK
This contains the `0.x` version of the SDK. This library is deprecated and all new integrations should use the new [Universal JavaScript library](https://github.com/extism/js-sdk#readme).

View File

@@ -1,23 +0,0 @@
const { build } = require("esbuild");
const { peerDependencies } = require('./package.json')
const sharedConfig = {
entryPoints: ["src/index.ts"],
bundle: true,
minify: false,
drop: [], // preseve debugger statements
external: Object.keys(peerDependencies || {}),
};
build({
...sharedConfig,
platform: 'node', // for CJS
outfile: "dist/index.js",
});
build({
...sharedConfig,
outfile: "dist/index.esm.js",
platform: 'neutral', // for ESM
format: "esm",
});

View File

@@ -1,248 +0,0 @@
<html>
<head>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<style>
#main {
width: 100%;
}
.manifest {
display: flex; /* or inline-flex */
flex-direction: row;
flex-wrap: nowrap;
width: 100%;
}
.urlInput {
width: 600px;
}
.funcName {
width: 150px;
}
.textAreas {
display: flex; /* or inline-flex */
flex-direction: row;
flex-wrap: nowrap;
width: 100%;
height: 300px;
}
.inputBox {
width: 100%;
height: 100%;
}
.inputBox > textarea {
width: 100%;
height: 100%;
}
.outputBox {
width: 100%;
height: 100%;
}
.outputBox > textarea {
width: 100%;
height: 100%;
}
.space {
height: 80px;
}
.dragAreas {
display: flex; /* or inline-flex */
flex-direction: row;
flex-wrap: nowrap;
width: 100%;
height: 200px;
}
.dragInput {
width: 100%;
height: 100%;
border-style: dotted;
border-color: #000;
}
.dragOutput {
width: 100%;
height: 100%;
}
.dropZone {
width: 100%;
height: 100%;
}
.outputImage {
width: 100%;
height: 100%;
}
</style>
<script type="text/babel">
function getBase64(file, cb) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
cb(reader.result)
};
reader.onerror = function (error) {
console.log("error")
};
}
function arrayTob64(buffer) {
var binary = '';
var bytes = [].slice.call(buffer);
bytes.forEach((b) => binary += String.fromCharCode(b));
return window.btoa(binary);
}
class App extends React.Component {
state = {
url: "https://raw.githubusercontent.com/extism/extism/main/wasm/code.wasm",
input: new Uint8Array(),
output: new Uint8Array(),
func_name: "count_vowels",
functions: []
}
async loadFunctions(url) {
let helloWorld = function(index){
console.log("Hello, " + this.allocator.getString(index));
return index;
};
let plugin = await this.extismContext.newPlugin({ "wasm": [ { "path": url } ] }, {"hello_world": helloWorld});
let functions = Object.keys(await plugin.getExports())
console.log("funcs ", functions)
this.setState({functions})
}
componentDidMount() {
this.loadFunctions(this.state.url)
}
constructor(props) {
super(props)
this.extismContext = props.extismContext
}
handleInputChange(e) {
e.preventDefault();
this.setState({ [e.target.name]: e.target.value })
if (e.target.name === "url") {
this.loadFunctions(e.target.value)
}
}
onInputKeyPress(e) {
if (e.keyCode == 13 && e.shiftKey == true) {
e.preventDefault()
this.handleOnRun()
}
}
async handleOnRun(e) {
e && e.preventDefault && e.preventDefault();
let helloWorld = function(index){
console.log("Hello, " + this.allocator.getString(index));
return index;
};
let plugin = await this.extismContext.newPlugin({ "wasm": [ { "path": this.state.url } ] }, {
"hello_world": helloWorld
});
let result = await plugin.call(this.state.func_name, this.state.input)
let output = result
this.setState({output})
}
nop = (e) => {
e.preventDefault();
e.stopPropagation();
};
handleDrop = e => {
e.preventDefault();
e.stopPropagation();
let files = [...e.dataTransfer.files];
if (files && files.length == 1) {
let file = files[0]
console.log(file)
file.arrayBuffer().then(b => {
this.setState({input: new Uint8Array(b)})
this.handleOnRun()
})
} else {
throw Error("Only one file please")
}
};
render() {
const funcOptions = this.state.functions.map(f => <option value={f}>{f}</option>)
let image = null
if (this.state.output) {
image = <img src={`data:image/png;base64,${arrayTob64(this.state.output)}`}/>
}
return <div className="app">
<div className="manifest">
<div>
<label>WASM Url: </label>
<input type="text" name="url" className="urlInput" value={this.state.url} onChange={this.handleInputChange.bind(this)} />
</div>
<div>
<label>Function: </label>
<select type="text" name="func_name" className="funcName" value={this.state.func_name} onChange={this.handleInputChange.bind(this)}>
{funcOptions}
</select>
</div>
<div>
<button onClick={this.handleOnRun.bind(this)}>Run</button>
</div>
</div>
<div className="textAreas">
<div className="inputBox">
<h3>Text Input</h3>
<textarea name="input" value={this.state.input} onChange={this.handleInputChange.bind(this)} onKeyDown={this.onInputKeyPress.bind(this)}></textarea>
</div>
<div className="outputBox">
<h3>Text Output</h3>
<textarea name="output" value={new TextDecoder().decode(this.state.output)} ></textarea>
</div>
</div>
<div className="space" />
<div className="dragAreas">
<div className="dragInput">
<h3>Image Input</h3>
<div className="dropZone"
onDrop={this.handleDrop.bind(this)}
onDragOver={this.nop.bind(this)}
onDragEnter={this.nop.bind(this)}
onDragLeave={this.nop.bind(this)}
>
</div>
</div>
<div className="dragOutput">
<h3>Image Output</h3>
<div className="outputImage">
{image}
</div>
</div>
</div>
</div>
}
}
window.App = App
</script>
<script type="module">
import {ExtismContext} from './dist/index.esm.js'
const e = React.createElement;
window.onload = () => {
const domContainer = document.getElementById('main');
console.log(domContainer)
const root = ReactDOM.createRoot(domContainer);
const extismContext = new ExtismContext()
root.render(e(App, {extismContext}));
}
</script>
</head>
<body>
<div id="main"></div>
</body>
</html>

View File

@@ -1,5 +0,0 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
};

14458
browser/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,39 +0,0 @@
{
"name": "@extism/runtime-browser",
"version": "0.3.1",
"description": "Extism runtime in the browser",
"scripts": {
"build": "node build.js && tsc --emitDeclarationOnly --outDir dist",
"format": "prettier --write \"src/**/*.ts\"",
"lint": "tslint -p tsconfig.json",
"test": "jest --config jest.config.js"
},
"private": false,
"publishConfig": {
"access": "public"
},
"files": [
"dist/*"
],
"module": "dist/index.esm.js",
"main": "dist/index.js",
"typings": "dist/src/index.d.ts",
"author": "The Extism Authors <oss@extism.org>",
"license": "BSD-3-Clause",
"devDependencies": {
"@types/jest": "^29.2.2",
"esbuild": "^0.15.13",
"esbuild-jest": "^0.5.0",
"jest": "^29.2.2",
"jest-environment-jsdom": "^29.3.1",
"prettier": "^2.7.1",
"ts-jest": "^29.0.3",
"tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0",
"typedoc": "^0.23.20",
"typescript": "^4.8.4"
},
"dependencies": {
"@bjorn3/browser_wasi_shim": "^0.2.7"
}
}

View File

@@ -1,104 +0,0 @@
type MemoryBlock = { offset: bigint; length: bigint };
export default class Allocator {
currentIndex: bigint;
active: Record<number, MemoryBlock>;
freed: MemoryBlock[];
memory: Uint8Array;
constructor(n: number) {
this.currentIndex = BigInt(1);
this.active = {};
this.freed = [];
this.memory = new Uint8Array(n);
}
reset() {
this.currentIndex = BigInt(1);
this.active = {};
this.freed = [];
}
alloc(length: bigint): bigint {
for (var i = 0; i < this.freed.length; i++) {
let block = this.freed[i];
if (block.length === length) {
this.active[Number(block.offset)] = block;
this.freed.splice(i, 1);
return block.offset;
} else if (block.length > length + BigInt(64)) {
const newBlock = { offset: block.offset, length };
block.offset += length;
block.length -= length;
return newBlock.offset;
}
}
// Resize memory if needed
// TODO: put a limit on the memory size
if (BigInt(this.memory.length) < this.currentIndex + length) {
const tmp = new Uint8Array(Number(this.currentIndex + length + BigInt(64)));
tmp.set(this.memory);
this.memory = tmp;
}
const offset = this.currentIndex;
this.currentIndex += length;
this.active[Number(offset)] = { offset, length };
return offset;
}
getBytes(offset: bigint): Uint8Array | null {
const block = this.active[Number(offset)];
if (!block) {
return null;
}
return new Uint8Array(this.memory.buffer, Number(offset), Number(block.length));
}
getString(offset: bigint): string | null {
const bytes = this.getBytes(offset);
if (bytes === null) {
return null;
}
return new TextDecoder().decode(bytes);
}
allocBytes(data: Uint8Array): bigint {
const offs = this.alloc(BigInt(data.length));
const bytes = this.getBytes(offs);
if (bytes === null) {
this.free(offs);
return BigInt(0);
}
bytes.set(data);
return offs;
}
allocString(data: string): bigint {
const bytes = new TextEncoder().encode(data);
return this.allocBytes(bytes);
}
getLength(offset: bigint): bigint {
const block = this.active[Number(offset)];
if (!block) {
return BigInt(0);
}
return block.length;
}
free(offset: bigint) {
const block = this.active[Number(offset)];
if (!block) {
return;
}
delete this.active[Number(offset)];
this.freed.push(block);
}
}

View File

@@ -1,45 +0,0 @@
import { Manifest, PluginConfig, ManifestWasmFile, ManifestWasmData } from './manifest';
import { ExtismPlugin } from './plugin';
/**
* Can be a {@link Manifest} or just the raw bytes of the WASM module as an ArrayBuffer.
* We recommend using {@link Manifest}
*/
type ManifestData = Manifest | ArrayBuffer | WebAssembly.Module;
/**
* A Context is needed to create plugins. The Context
* is where your plugins live. Freeing the context
* frees all of the plugins in its scope.
*/
export default class ExtismContext {
/**
* Create a plugin managed by this context
*
* @param manifest - The {@link ManifestData} describing the plugin code and config
* @param config - Config details for the plugin
* @returns A new Plugin scoped to this Context
*/
async newPlugin(manifest: ManifestData, functions: Record<string, any> = {}, config?: PluginConfig) {
let moduleData: ArrayBuffer | WebAssembly.Module | null = null;
if (manifest instanceof ArrayBuffer || manifest instanceof WebAssembly.Module) {
moduleData = manifest;
} else if ((manifest as Manifest).wasm) {
const wasmData = (manifest as Manifest).wasm;
if (wasmData.length > 1) throw Error('This runtime only supports one module in Manifest.wasm');
const wasm = wasmData[0];
if ((wasm as ManifestWasmData).data) {
moduleData = (wasm as ManifestWasmData).data;
} else if ((wasm as ManifestWasmFile).path) {
const response = await fetch((wasm as ManifestWasmFile).path);
moduleData = await response.arrayBuffer();
console.dir(moduleData);
}
}
if (!moduleData) {
throw Error(`Unsure how to interpret manifest ${manifest}`);
}
return new ExtismPlugin(moduleData, functions, config);
}
}

View File

@@ -1,24 +0,0 @@
import { ExtismContext } from './';
import fs from 'fs';
import path from 'path';
function parse(bytes: Uint8Array): any {
return JSON.parse(new TextDecoder().decode(bytes));
}
describe('', () => {
it('can load and call a plugin', async () => {
// const data = fs.readFileSync(path.join(__dirname, '..', 'data', 'code.wasm'));
// const ctx = new ExtismContext();
// const plugin = await ctx.newPlugin({ wasm: [{ data: data }] });
// const functions = await plugin.getExports();
// expect(Object.keys(functions).filter((x) => !x.startsWith('__') && x !== 'memory')).toEqual(['count_vowels']);
// let output = await plugin.call('count_vowels', 'this is a test');
// expect(parse(output)).toEqual({ count: 4 });
// output = await plugin.call('count_vowels', 'this is a test again');
// expect(parse(output)).toEqual({ count: 7 });
// output = await plugin.call('count_vowels', 'this is a test thrice');
// expect(parse(output)).toEqual({ count: 6 });
expect(true).toEqual(true);
});
});

View File

@@ -1,4 +0,0 @@
import ExtismContext from './context';
import { ExtismFunction, ExtismPlugin } from './plugin';
export { ExtismContext, ExtismFunction, ExtismPlugin };

View File

@@ -1,40 +0,0 @@
/**
* Represents a path or url to a WASM module
*/
export type ManifestWasmFile = {
path: string;
name?: string;
hash?: string;
};
/**
* Represents the raw bytes of a WASM file loaded into memory
*/
export type ManifestWasmData = {
data: Uint8Array;
name?: string;
hash?: string;
};
/**
* {@link ExtismPlugin} Config
*/
export type PluginConfig = Map<string, string>;
/**
* The WASM to load as bytes or a path
*/
export type ManifestWasm = ManifestWasmFile | ManifestWasmData;
/**
* The manifest which describes the {@link ExtismPlugin} code and
* runtime constraints.
*
* @see [Extism > Concepts > Manifest](https://extism.org/docs/concepts/manifest)
*/
export type Manifest = {
wasm: Array<ManifestWasm>;
//memory?: ManifestMemory;
config?: PluginConfig;
allowed_hosts?: Array<string>;
};

View File

@@ -1,217 +0,0 @@
import Allocator from './allocator';
import { PluginConfig } from './manifest';
import { WASI, Fd } from '@bjorn3/browser_wasi_shim';
export type ExtismFunction = any;
export class ExtismPlugin {
moduleData: ArrayBuffer | WebAssembly.Module;
allocator: Allocator;
config?: PluginConfig;
vars: Record<string, Uint8Array>;
input: Uint8Array;
output: Uint8Array;
module?: WebAssembly.WebAssemblyInstantiatedSource;
functions: Record<string, ExtismFunction>;
constructor(moduleData: ArrayBuffer | WebAssembly.Module, functions: Record<string, ExtismFunction> = {}, config?: PluginConfig) {
this.moduleData = moduleData;
this.allocator = new Allocator(1024 * 1024);
this.config = config;
this.vars = {};
this.input = new Uint8Array();
this.output = new Uint8Array();
this.functions = functions;
}
async getExports(): Promise<WebAssembly.Exports> {
const module = await this._instantiateModule();
return module.instance.exports;
}
async getImports(): Promise<WebAssembly.ModuleImportDescriptor[]> {
const module = await this._instantiateModule();
return WebAssembly.Module.imports(module.module);
}
async getInstance(): Promise<WebAssembly.Instance> {
const module = await this._instantiateModule();
return module.instance;
}
async call(func_name: string, input: Uint8Array | string): Promise<Uint8Array> {
const module = await this._instantiateModule();
if (typeof input === 'string') {
this.input = new TextEncoder().encode(input);
} else if (input instanceof Uint8Array) {
this.input = input;
} else {
throw new Error('input should be string or Uint8Array');
}
this.allocator.reset();
let func = module.instance.exports[func_name];
if (!func) {
throw Error(`function does not exist ${func_name}`);
}
//@ts-ignore
func();
return this.output;
}
async _instantiateModule(): Promise<WebAssembly.WebAssemblyInstantiatedSource> {
if (this.module) {
return this.module;
}
const environment = this.makeEnv();
const args: Array<string> = [];
const envVars: Array<string> = [];
let fds: Fd[] = [
// new XtermStdio(term), // stdin
// new XtermStdio(term), // stdout
// new XtermStdio(term), // stderr
];
let wasi = new WASI(args, envVars, fds);
let env = {
wasi_snapshot_preview1: wasi.wasiImport,
env: environment,
};
if (this.moduleData instanceof WebAssembly.Module) {
const instance = new WebAssembly.Instance(this.moduleData, env);
this.module = {
instance,
module: this.moduleData
}
//@ts-ignore
wasi.inst = instance;
}
else {
this.module = await WebAssembly.instantiate(this.moduleData, env);
//@ts-ignore
wasi.inst = this.module.instance;
}
if (!this.module) throw Error("Unable to instantiate module");
// normally we would call wasi.start here but it doesn't respect when there is
// no _start function
if (this.module.instance.exports._start) {
//@ts-ignore
this.module.instance.exports._start();
}
return this.module;
}
makeEnv(): any {
const plugin = this;
var env: any = {
extism_alloc(n: bigint): bigint {
return plugin.allocator.alloc(n);
},
extism_free(n: bigint) {
plugin.allocator.free(n);
},
extism_load_u8(n: bigint): number {
return plugin.allocator.memory[Number(n)];
},
extism_load_u64(n: bigint): bigint {
let cast = new DataView(plugin.allocator.memory.buffer, Number(n));
return cast.getBigUint64(0, true);
},
extism_store_u8(offset: bigint, n: number) {
plugin.allocator.memory[Number(offset)] = Number(n);
},
extism_store_u64(offset: bigint, n: bigint) {
const tmp = new DataView(plugin.allocator.memory.buffer, Number(offset));
tmp.setBigUint64(0, n, true);
},
extism_input_length(): bigint {
return BigInt(plugin.input.length);
},
extism_input_load_u8(i: bigint): number {
return plugin.input[Number(i)];
},
extism_input_load_u64(idx: bigint): bigint {
let cast = new DataView(plugin.input.buffer, Number(idx));
return cast.getBigUint64(0, true);
},
extism_output_set(offset: bigint, length: bigint) {
const offs = Number(offset);
const len = Number(length);
plugin.output = plugin.allocator.memory.slice(offs, offs + len);
},
extism_error_set(i: bigint) {
throw plugin.allocator.getString(i);
},
extism_config_get(i: bigint): bigint {
if (typeof plugin.config === 'undefined') {
return BigInt(0);
}
const key = plugin.allocator.getString(i);
if (key === null) {
return BigInt(0);
}
const value = plugin.config.get(key);
if (typeof value === 'undefined') {
return BigInt(0);
}
return plugin.allocator.allocString(value);
},
extism_var_get(i: bigint): bigint {
const key = plugin.allocator.getString(i);
if (key === null) {
return BigInt(0);
}
const value = plugin.vars[key];
if (typeof value === 'undefined') {
return BigInt(0);
}
return plugin.allocator.allocBytes(value);
},
extism_var_set(n: bigint, i: bigint) {
const key = plugin.allocator.getString(n);
if (key === null) {
return;
}
const value = plugin.allocator.getBytes(i);
if (value === null) {
return;
}
plugin.vars[key] = value;
},
extism_http_request(n: bigint, i: bigint): number {
debugger;
return 0;
},
extism_length(i: bigint): bigint {
return plugin.allocator.getLength(i);
},
extism_log_warn(i: bigint) {
const s = plugin.allocator.getString(i);
console.warn(s);
},
extism_log_info(i: bigint) {
const s = plugin.allocator.getString(i);
console.log(s);
},
extism_log_debug(i: bigint) {
const s = plugin.allocator.getString(i);
console.debug(s);
},
extism_log_error(i: bigint) {
const s = plugin.allocator.getString(i);
console.error(s);
},
};
for (const [name, func] of Object.entries(this.functions)) {
env[name] = function () {
return func.apply(plugin, arguments);
};
}
return env;
}
}

View File

@@ -1,13 +0,0 @@
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"strict": true,
"skipLibCheck": true,
"allowJs": true
},
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}

View File

@@ -1,6 +0,0 @@
{
"extends": [
"tslint:recommended",
"tslint-config-prettier"
]
}

View File

@@ -1,2 +0,0 @@
build:
clang -g -o main main.c -lextism -L .

View File

@@ -1,49 +0,0 @@
{
"name": "extism/extism",
"description": "Make your software programmable. Run WebAssembly extensions in your app using the first off-the-shelf, universal plug-in system.",
"license": "BSD-3-Clause",
"type": "library",
"keywords": [
"WebAssembly",
"plugin-system",
"runtime",
"plug-in"
],
"authors": [
{
"name": "The Extism Authors",
"email": "oss@extism.org",
"homepage": "https://extism.org"
},
{
"name": "Dylibso, Inc.",
"email": "oss@dylib.so",
"homepage": "https://dylib.so"
}
],
"require": {
"php": "^7.4 || ^8",
"ircmaxell/ffime": "dev-master"
},
"suggest": {},
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"Extism\\": "php/src/"
},
"files": [
"php/src/Context.php",
"php/src/Plugin.php"
]
},
"autoload-dev": {
"psr-4": {}
},
"config": {
"sort-packages": true
},
"extra": {},
"scripts": {},
"scripts-descriptions": {}
}

163
composer.lock generated
View File

@@ -1,163 +0,0 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0e0352cd3a96e03fd9c964888deedb29",
"packages": [
{
"name": "ircmaxell/ffime",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/ircmaxell/FFIMe.git",
"reference": "431a3c13d9906b974d50b13bf8295097ea000c5e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ircmaxell/FFIMe/zipball/431a3c13d9906b974d50b13bf8295097ea000c5e",
"reference": "431a3c13d9906b974d50b13bf8295097ea000c5e",
"shasum": ""
},
"require": {
"ircmaxell/php-c-parser": "dev-master",
"ircmaxell/php-object-symbolresolver": "dev-master",
"php": ">=8.0"
},
"require-dev": {
"phpunit/phpunit": "^8.0"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-4": {
"FFIMe\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Anthony Ferrara",
"email": "ircmaxell@gmail.com"
}
],
"description": "Make life easy when working with 7.4's FFI",
"support": {
"issues": "https://github.com/ircmaxell/FFIMe/issues",
"source": "https://github.com/ircmaxell/FFIMe/tree/master"
},
"time": "2023-04-03T00:43:12+00:00"
},
{
"name": "ircmaxell/php-c-parser",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/ircmaxell/php-c-parser.git",
"reference": "29e0223704e4ee00c66f43506f5f52db151b3517"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ircmaxell/php-c-parser/zipball/29e0223704e4ee00c66f43506f5f52db151b3517",
"reference": "29e0223704e4ee00c66f43506f5f52db151b3517",
"shasum": ""
},
"require": {
"php": ">=7.4"
},
"require-dev": {
"ircmaxell/php-yacc": "dev-master",
"phpunit/phpunit": "^8.0"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-4": {
"PHPCParser\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Anthony Ferrara",
"email": "ircmaxell@gmail.com"
},
{
"name": "Bob Weinand",
"email": "bobwei9@hotmail.com"
}
],
"description": "Parse C when using PHP",
"support": {
"issues": "https://github.com/ircmaxell/php-c-parser/issues",
"source": "https://github.com/ircmaxell/php-c-parser/tree/master"
},
"time": "2023-03-23T10:58:24+00:00"
},
{
"name": "ircmaxell/php-object-symbolresolver",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/ircmaxell/php-object-symbolresolver.git",
"reference": "dfe1b1aa6c15b198bdef50fff8485e98e89f2a09"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ircmaxell/php-object-symbolresolver/zipball/dfe1b1aa6c15b198bdef50fff8485e98e89f2a09",
"reference": "dfe1b1aa6c15b198bdef50fff8485e98e89f2a09",
"shasum": ""
},
"require": {
"php": ">=7.4"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-4": {
"PHPObjectSymbolResolver\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Anthony Ferrara",
"email": "ircmaxell@gmail.com"
},
{
"name": "Bob Weinand",
"email": "bobwei9@hotmail.com"
}
],
"description": "An object file (ELF, Mach-O) parser",
"support": {
"issues": "https://github.com/ircmaxell/php-object-symbolresolver/issues",
"source": "https://github.com/ircmaxell/php-object-symbolresolver/tree/master"
},
"time": "2022-09-15T18:21:50+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": {
"ircmaxell/ffime": 20
},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
"php": "^7.4 || ^8"
},
"platform-dev": [],
"plugin-api-version": "2.3.0"
}

26
convert-macros/Cargo.toml Normal file
View File

@@ -0,0 +1,26 @@
[package]
name = "extism-convert-macros"
edition.workspace = true
authors.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
version.workspace = true
description = "Macros to remove boilerplate with Extism"
[lib]
proc-macro = true
[features]
extism-path = []
extism-pdk-path = []
[dependencies]
manyhow.version = "0.11.0"
proc-macro-crate = "3.1.0"
proc-macro2 = "1.0.78"
quote = "1.0.35"
syn = { version = "2.0.48", features = ["derive"] }
[dev-dependencies]
trybuild = "1.0.89"

108
convert-macros/src/lib.rs Normal file
View File

@@ -0,0 +1,108 @@
use std::iter;
use manyhow::{ensure, error_message, manyhow, Result};
use proc_macro_crate::{crate_name, FoundCrate};
use quote::{format_ident, quote, ToTokens};
use syn::{parse_quote, Attribute, DeriveInput, Path};
/// Tries to resolve the path to `extism_convert` dynamically, falling back to feature flags when unsuccessful.
fn convert_path() -> Path {
match (
crate_name("extism"),
crate_name("extism-convert"),
crate_name("extism-pdk"),
) {
(Ok(FoundCrate::Name(name)), ..) => {
let ident = format_ident!("{name}");
parse_quote!(::#ident::convert)
}
(_, Ok(FoundCrate::Name(name)), ..) | (.., Ok(FoundCrate::Name(name))) => {
let ident = format_ident!("{name}");
parse_quote!(::#ident)
}
(Ok(FoundCrate::Itself), ..) => parse_quote!(::extism::convert),
(_, Ok(FoundCrate::Itself), ..) => parse_quote!(::extism_convert),
(.., Ok(FoundCrate::Itself)) => parse_quote!(::extism_pdk),
_ if cfg!(feature = "extism-path") => parse_quote!(::extism::convert),
_ if cfg!(feature = "extism-pdk-path") => parse_quote!(::extism_pdk),
_ => parse_quote!(::extism_convert),
}
}
fn extract_encoding(attrs: &[Attribute]) -> Result<Path> {
let encodings: Vec<_> = attrs
.iter()
.filter(|attr| attr.path().is_ident("encoding"))
.collect();
ensure!(!encodings.is_empty(), "encoding needs to be specified"; try = "`#[encoding(Json)]`");
ensure!(encodings.len() < 2, encodings[1], "only one encoding can be specified"; try = "remove `{}`", encodings[1].to_token_stream());
Ok(encodings[0].parse_args().map_err(
|e| error_message!(e.span(), "{e}"; note= "expects a path"; try = "`#[encoding(Json)]`"),
)?)
}
#[manyhow]
#[proc_macro_derive(ToBytes, attributes(encoding))]
pub fn to_bytes(
DeriveInput {
attrs,
ident,
generics,
..
}: DeriveInput,
) -> Result {
let encoding = extract_encoding(&attrs)?;
let convert = convert_path();
let (_, type_generics, _) = generics.split_for_impl();
let mut generics = generics.clone();
generics.make_where_clause().predicates.push(
parse_quote!(for<'__to_bytes_b> #encoding<&'__to_bytes_b Self>: #convert::ToBytes<'__to_bytes_b>)
);
generics.params = iter::once(parse_quote!('__to_bytes_a))
.chain(generics.params)
.collect();
let (impl_generics, _, where_clause) = generics.split_for_impl();
Ok(quote! {
impl #impl_generics #convert::ToBytes<'__to_bytes_a> for #ident #type_generics #where_clause
{
type Bytes = ::std::vec::Vec<u8>;
fn to_bytes(&self) -> Result<Self::Bytes, #convert::Error> {
#convert::ToBytes::to_bytes(&#encoding(self)).map(|__bytes| __bytes.as_ref().to_vec())
}
}
})
}
#[manyhow]
#[proc_macro_derive(FromBytes, attributes(encoding))]
pub fn from_bytes(
DeriveInput {
attrs,
ident,
mut generics,
..
}: DeriveInput,
) -> Result {
let encoding = extract_encoding(&attrs)?;
let convert = convert_path();
generics
.make_where_clause()
.predicates
.push(parse_quote!(#encoding<Self>: #convert::FromBytesOwned));
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
Ok(quote! {
impl #impl_generics #convert::FromBytesOwned for #ident #type_generics #where_clause
{
fn from_bytes_owned(__data: &[u8]) -> Result<Self, #convert::Error> {
<#encoding<Self> as #convert::FromBytesOwned>::from_bytes_owned(__data).map(|__encoding| __encoding.0)
}
}
})
}

View File

@@ -0,0 +1,5 @@
#[test]
fn ui() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/ui/*.rs");
}

View File

@@ -0,0 +1,23 @@
use extism_convert_macros::ToBytes;
#[derive(ToBytes)]
struct MissingEncoding;
#[derive(ToBytes)]
#[encoding]
struct EmptyAttr;
#[derive(ToBytes)]
#[encoding = "string"]
struct EqNoParen;
#[derive(ToBytes)]
#[encoding(something, else)]
struct NotAPath;
#[derive(ToBytes)]
#[encoding(Multiple)]
#[encoding(Encodings)]
struct MultipleEncodings;
fn main() {}

View File

@@ -0,0 +1,44 @@
error: encoding needs to be specified
= try: `#[encoding(Json)]`
--> tests/ui/invalid-encoding.rs:3:10
|
3 | #[derive(ToBytes)]
| ^^^^^^^
|
= note: this error originates in the derive macro `ToBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected attribute arguments in parentheses: #[encoding(...)]
= note: expects a path
= try: `#[encoding(Json)]`
--> tests/ui/invalid-encoding.rs:7:3
|
7 | #[encoding]
| ^^^^^^^^
error: expected parentheses: #[encoding(...)]
= note: expects a path
= try: `#[encoding(Json)]`
--> tests/ui/invalid-encoding.rs:11:12
|
11 | #[encoding = "string"]
| ^
error: unexpected token
= note: expects a path
= try: `#[encoding(Json)]`
--> tests/ui/invalid-encoding.rs:15:21
|
15 | #[encoding(something, else)]
| ^
error: only one encoding can be specified
= try: remove `#[encoding(Encodings)]`
--> tests/ui/invalid-encoding.rs:20:1
|
20 | #[encoding(Encodings)]
| ^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -1,26 +1,31 @@
[package]
name = "extism-convert"
version = "0.2.0"
edition = "2021"
authors = ["The Extism Authors", "oss@extism.org"]
license = "BSD-3-Clause"
readme = "./README.md"
homepage = "https://extism.org"
repository = "https://github.com/extism/extism"
edition.workspace = true
authors.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
version.workspace = true
description = "Traits to make Rust types usable with Extism"
[dependencies]
anyhow = "1.0.75"
base64 = "0.21.3"
prost = { version = "0.12.0", optional = true }
base64 = "~0.22"
bytemuck = {version = "1.14.0", optional = true }
prost = { version = "0.13.1", optional = true }
protobuf = { version = "3.2.0", optional = true }
rmp-serde = { version = "1.1.2", optional = true }
serde = "1.0.186"
serde_json = "1.0.105"
extism-convert-macros.workspace = true
[dev-dependencies]
serde = {version = "1.0.186", features = ["derive"]}
serde = { version = "1.0.186", features = ["derive"] }
[features]
default = ["msgpack", "protobuf"]
default = ["msgpack", "prost", "raw"]
msgpack = ["rmp-serde"]
protobuf = ["prost"]
raw = ["bytemuck"]
extism-path = ["extism-convert-macros/extism-path"]
extism-pdk-path = ["extism-convert-macros/extism-pdk-path"]

View File

@@ -11,13 +11,14 @@ use base64::Engine;
/// extism_convert::encoding!(MyJson, serde_json::to_vec, serde_json::from_slice);
/// ```
///
/// This will create a struct `struct MyJson<T>(pub T)` and implement `ToBytes` using `serde_json::to_vec`
/// and `FromBytesOwned` using `serde_json::from_vec`
/// This will create a struct `struct MyJson<T>(pub T)` and implement [`ToBytes`] using [`serde_json::to_vec`]
/// and [`FromBytesOwned`] using [`serde_json::from_slice`]
#[macro_export]
macro_rules! encoding {
($name:ident, $to_vec:expr, $from_slice:expr) => {
($pub:vis $name:ident, $to_vec:expr, $from_slice:expr) => {
#[doc = concat!(stringify!($name), " encoding")]
pub struct $name<T>(pub T);
#[derive(Debug)]
$pub struct $name<T>(pub T);
impl<T> $name<T> {
pub fn into_inner(self) -> T {
@@ -25,6 +26,12 @@ macro_rules! encoding {
}
}
impl<T> From<T> for $name<T> {
fn from(data: T) -> Self {
Self(data)
}
}
impl<T: serde::de::DeserializeOwned> $crate::FromBytesOwned for $name<T> {
fn from_bytes_owned(data: &[u8]) -> std::result::Result<Self, $crate::Error> {
let x = $from_slice(data)?;
@@ -43,12 +50,12 @@ macro_rules! encoding {
};
}
encoding!(Json, serde_json::to_vec, serde_json::from_slice);
encoding!(pub Json, serde_json::to_vec, serde_json::from_slice);
#[cfg(feature = "msgpack")]
encoding!(Msgpack, rmp_serde::to_vec, rmp_serde::from_slice);
encoding!(pub Msgpack, rmp_serde::to_vec, rmp_serde::from_slice);
impl<'a> ToBytes<'a> for serde_json::Value {
impl ToBytes<'_> for serde_json::Value {
type Bytes = Vec<u8>;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -69,9 +76,16 @@ impl FromBytesOwned for serde_json::Value {
///
/// A value wrapped in `Base64` will automatically be encoded/decoded using base64, the inner value should not
/// already be base64 encoded.
#[derive(Debug)]
pub struct Base64<T: AsRef<[u8]>>(pub T);
impl<'a, T: AsRef<[u8]>> ToBytes<'a> for Base64<T> {
impl<T: AsRef<[u8]>> From<T> for Base64<T> {
fn from(data: T) -> Self {
Self(data)
}
}
impl<T: AsRef<[u8]>> ToBytes<'_> for Base64<T> {
type Bytes = String;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -98,11 +112,19 @@ impl FromBytesOwned for Base64<String> {
/// Protobuf encoding
///
/// Allows for `prost` Protobuf messages to be used as arguments to Extism plugin calls
#[cfg(feature = "protobuf")]
pub struct Protobuf<T: prost::Message>(pub T);
#[cfg(feature = "prost")]
#[derive(Debug)]
pub struct Prost<T: prost::Message>(pub T);
#[cfg(feature = "protobuf")]
impl<'a, T: prost::Message> ToBytes<'a> for Protobuf<T> {
#[cfg(feature = "prost")]
impl<T: prost::Message> From<T> for Prost<T> {
fn from(data: T) -> Self {
Self(data)
}
}
#[cfg(feature = "prost")]
impl<T: prost::Message> ToBytes<'_> for Prost<T> {
type Bytes = Vec<u8>;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -110,9 +132,56 @@ impl<'a, T: prost::Message> ToBytes<'a> for Protobuf<T> {
}
}
#[cfg(feature = "protobuf")]
impl<T: Default + prost::Message> FromBytesOwned for Protobuf<T> {
#[cfg(feature = "prost")]
impl<T: Default + prost::Message> FromBytesOwned for Prost<T> {
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
Ok(Protobuf(T::decode(data)?))
Ok(Prost(T::decode(data)?))
}
}
/// Protobuf encoding
///
/// Allows for `rust-protobuf` Protobuf messages to be used as arguments to Extism plugin calls
#[cfg(feature = "protobuf")]
pub struct Protobuf<T: protobuf::Message>(pub T);
#[cfg(feature = "protobuf")]
impl<T: protobuf::Message> ToBytes<'_> for Protobuf<T> {
type Bytes = Vec<u8>;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
Ok(self.0.write_to_bytes()?)
}
}
#[cfg(feature = "protobuf")]
impl<T: Default + protobuf::Message> FromBytesOwned for Protobuf<T> {
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
Ok(Protobuf(T::parse_from_bytes(data)?))
}
}
/// Raw does no conversion, it just copies the memory directly.
/// Note: This will only work for types that implement [bytemuck::Pod](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html)
#[cfg(all(feature = "raw", target_endian = "little"))]
pub struct Raw<'a, T: bytemuck::Pod>(pub &'a T);
#[cfg(all(feature = "raw", target_endian = "little"))]
impl<'a, T: bytemuck::Pod> ToBytes<'a> for Raw<'a, T> {
type Bytes = &'a [u8];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
Ok(bytemuck::bytes_of(self.0))
}
}
#[cfg(all(feature = "raw", target_endian = "little"))]
impl<'a, T: bytemuck::Pod> FromBytes<'a> for Raw<'a, T> {
fn from_bytes(data: &'a [u8]) -> Result<Self, Error> {
let x = bytemuck::try_from_bytes(data).map_err(|x| Error::msg(x.to_string()))?;
Ok(Raw(x))
}
}
#[cfg(all(feature = "raw", target_endian = "big"))]
compile_error!("The raw feature is only supported on little endian targets");

View File

@@ -1,14 +1,68 @@
use crate::*;
pub use extism_convert_macros::FromBytes;
/// `FromBytes` is used to define how a type should be decoded when working with
/// Extism memory. It is used for plugin output and host function input.
///
/// `FromBytes` can be derived by delegating encoding to generic type implementing
/// `FromBytes`, e.g., [`Json`], [`Msgpack`].
///
/// ```
/// use extism_convert::{Json, FromBytes};
/// use serde::Deserialize;
///
/// #[derive(FromBytes, Deserialize, PartialEq, Debug)]
/// #[encoding(Json)]
/// struct Struct {
/// hello: String,
/// }
///
/// assert_eq!(Struct::from_bytes(br#"{"hello":"hi"}"#)?, Struct { hello: "hi".into() });
/// # Ok::<(), extism_convert::Error>(())
/// ```
///
/// Custom encodings can also be used, through new-types with a single generic
/// argument, i.e., `Type<T>(T)`, that implement `FromBytesOwned` for the struct.
///
/// ```
/// use std::str::{self, FromStr};
/// use std::convert::Infallible;
/// use extism_convert::{Error, FromBytes, FromBytesOwned};
///
/// // Custom serialization using `FromStr`
/// struct StringEnc<T>(T);
/// impl<T: FromStr> FromBytesOwned for StringEnc<T> where Error: From<<T as FromStr>::Err> {
/// fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
/// Ok(Self(str::from_utf8(data)?.parse()?))
/// }
/// }
///
/// #[derive(FromBytes, PartialEq, Debug)]
/// #[encoding(StringEnc)]
/// struct Struct {
/// hello: String,
/// }
///
/// impl FromStr for Struct {
/// type Err = Infallible;
/// fn from_str(s: &str) -> Result<Self, Infallible> {
/// Ok(Self { hello: s.to_owned() })
/// }
/// }
///
/// assert_eq!(Struct::from_bytes(b"hi")?, Struct { hello: "hi".into() });
/// # Ok::<(), extism_convert::Error>(())
/// ```
pub trait FromBytes<'a>: Sized {
/// Decode a value from a slice of bytes
fn from_bytes(data: &'a [u8]) -> Result<Self, Error>;
}
/// `FromBytesOwned` is similar to `FromBytes` but it doesn't borrow from the input slice.
/// `FromBytes` is automatically implemented for all types that implement `FromBytesOwned`
/// `FromBytesOwned` is similar to [`FromBytes`] but it doesn't borrow from the input slice.
/// [`FromBytes`] is automatically implemented for all types that implement `FromBytesOwned`.
///
/// `FromBytesOwned` can be derived through [`#[derive(FromBytes)]`](FromBytes).
pub trait FromBytesOwned: Sized {
/// Decode a value from a slice of bytes, the resulting value should not borrow the input
/// data.
@@ -87,6 +141,16 @@ impl FromBytesOwned for u32 {
}
}
impl FromBytesOwned for bool {
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
if let Some(x) = data.first() {
Ok(*x != 0)
} else {
Err(Error::msg("Expected one byte to read boolean value"))
}
}
}
impl FromBytesOwned for () {
fn from_bytes_owned(_: &[u8]) -> Result<Self, Error> {
Ok(())
@@ -98,3 +162,13 @@ impl<'a, T: FromBytes<'a>> FromBytes<'a> for std::io::Cursor<T> {
Ok(std::io::Cursor::new(T::from_bytes(data)?))
}
}
impl<'a, T: FromBytes<'a>> FromBytes<'a> for Option<T> {
fn from_bytes(data: &'a [u8]) -> Result<Self, Error> {
if data.is_empty() {
return Ok(None);
}
T::from_bytes(data).map(Some)
}
}

View File

@@ -5,6 +5,9 @@
//! similar to [axum extractors](https://docs.rs/axum/latest/axum/extract/index.html#intro) - they are
//! implemented as a tuple struct with a single field that is meant to be extracted using pattern matching.
// Makes proc-macros able to resolve `::extism_convert` correctly
extern crate self as extism_convert;
pub use anyhow::Error;
mod encoding;
@@ -18,9 +21,15 @@ pub use encoding::{Base64, Json};
#[cfg(feature = "msgpack")]
pub use encoding::Msgpack;
#[cfg(feature = "prost")]
pub use encoding::Prost;
#[cfg(feature = "protobuf")]
pub use encoding::Protobuf;
#[cfg(all(feature = "raw", target_endian = "little"))]
pub use encoding::Raw;
pub use from_bytes::{FromBytes, FromBytesOwned};
pub use memory_handle::MemoryHandle;
pub use to_bytes::ToBytes;

View File

@@ -20,6 +20,7 @@ fn roundtrip_json() {
}
#[test]
#[cfg(feature = "msgpack")]
fn roundtrip_msgpack() {
let x = Testing {
a: "foobar".to_string(),
@@ -37,3 +38,64 @@ fn roundtrip_base64() {
let Base64(s): Base64<String> = FromBytes::from_bytes(bytes.as_bytes()).unwrap();
assert_eq!(s, "this is a test");
}
#[test]
fn rountrip_option() {
// `None` case
let e0: Option<Json<Testing>> = FromBytes::from_bytes(&[]).unwrap();
let b = e0.to_bytes().unwrap();
let e1: Option<Json<Testing>> = FromBytes::from_bytes(&b).unwrap();
assert!(e0.is_none());
assert_eq!(e0.is_none(), e1.is_none());
// `Some` case
let x = Testing {
a: "foobar".to_string(),
b: 123,
c: 456.7,
};
let bytes = Json(&x).to_bytes().unwrap();
let y: Option<Json<Testing>> = FromBytes::from_bytes(&bytes).unwrap();
let b = ToBytes::to_bytes(&y).unwrap();
let z: Option<Json<Testing>> = FromBytes::from_bytes(&b).unwrap();
assert_eq!(y.unwrap().0, z.unwrap().0);
}
#[test]
fn check_bool() {
// `None` case
let a = true.to_bytes().unwrap();
let b = false.to_bytes().unwrap();
assert_ne!(a, b);
assert_eq!(a, [1]);
assert_eq!(b, [0]);
}
#[cfg(all(feature = "raw", target_endian = "little"))]
mod raw_tests {
use crate::*;
#[test]
fn test_raw() {
#[derive(Debug, Clone, Copy, PartialEq)]
struct TestRaw {
a: i32,
b: f64,
c: bool,
}
unsafe impl bytemuck::Pod for TestRaw {}
unsafe impl bytemuck::Zeroable for TestRaw {}
let x = TestRaw {
a: 123,
b: 45678.91011,
c: true,
};
let raw = Raw(&x).to_bytes().unwrap();
let y = Raw::from_bytes(raw).unwrap();
assert_eq!(&x, y.0);
let y: Result<Raw<[u8; std::mem::size_of::<TestRaw>()]>, Error> = Raw::from_bytes(raw);
assert!(y.is_ok());
}
}

View File

@@ -1,7 +1,58 @@
use crate::*;
pub use extism_convert_macros::ToBytes;
/// `ToBytes` is used to define how a type should be encoded when working with
/// Extism memory. It is used for plugin input and host function output.
///
/// `ToBytes` can be derived by delegating encoding to generic type implementing
/// `ToBytes`, e.g., [`Json`], [`Msgpack`].
///
/// ```
/// use extism_convert::{Json, ToBytes};
/// use serde::Serialize;
///
/// #[derive(ToBytes, Serialize)]
/// #[encoding(Json)]
/// struct Struct {
/// hello: String,
/// }
///
/// assert_eq!(Struct { hello: "hi".into() }.to_bytes()?, br#"{"hello":"hi"}"#);
/// # Ok::<(), extism_convert::Error>(())
/// ```
///
/// But custom types can also be used, as long as they are new-types with a single
/// generic argument, i.e., `Type<T>(T)`, that implement `ToBytes` for the struct.
///
/// ```
/// use extism_convert::{Error, ToBytes};
///
/// // Custom serialization using `ToString`
/// struct StringEnc<T>(T);
/// impl<T: ToString> ToBytes<'_> for StringEnc<&T> {
/// type Bytes = String;
///
/// fn to_bytes(&self) -> Result<String, Error> {
/// Ok(self.0.to_string())
/// }
/// }
///
/// #[derive(ToBytes)]
/// #[encoding(StringEnc)]
/// struct Struct {
/// hello: String,
/// }
///
/// impl ToString for Struct {
/// fn to_string(&self) -> String {
/// self.hello.clone()
/// }
/// }
///
/// assert_eq!(Struct { hello: "hi".into() }.to_bytes()?, b"hi");
/// # Ok::<(), Error>(())
/// ```
pub trait ToBytes<'a> {
/// A configurable byte slice representation, allows any type that implements `AsRef<[u8]>`
type Bytes: AsRef<[u8]>;
@@ -10,21 +61,21 @@ pub trait ToBytes<'a> {
fn to_bytes(&self) -> Result<Self::Bytes, Error>;
}
impl<'a> ToBytes<'a> for () {
impl ToBytes<'_> for () {
type Bytes = [u8; 0];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
Ok([])
}
}
impl<'a> ToBytes<'a> for Vec<u8> {
impl ToBytes<'_> for Vec<u8> {
type Bytes = Vec<u8>;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
Ok(self.clone())
}
}
impl<'a> ToBytes<'a> for String {
impl ToBytes<'_> for String {
type Bytes = String;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
Ok(self.clone())
@@ -45,7 +96,7 @@ impl<'a> ToBytes<'a> for &'a str {
}
}
impl<'a> ToBytes<'a> for f64 {
impl ToBytes<'_> for f64 {
type Bytes = [u8; 8];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -53,7 +104,7 @@ impl<'a> ToBytes<'a> for f64 {
}
}
impl<'a> ToBytes<'a> for f32 {
impl ToBytes<'_> for f32 {
type Bytes = [u8; 4];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -61,7 +112,7 @@ impl<'a> ToBytes<'a> for f32 {
}
}
impl<'a> ToBytes<'a> for i64 {
impl ToBytes<'_> for i64 {
type Bytes = [u8; 8];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -69,7 +120,7 @@ impl<'a> ToBytes<'a> for i64 {
}
}
impl<'a> ToBytes<'a> for i32 {
impl ToBytes<'_> for i32 {
type Bytes = [u8; 4];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -77,7 +128,7 @@ impl<'a> ToBytes<'a> for i32 {
}
}
impl<'a> ToBytes<'a> for u64 {
impl ToBytes<'_> for u64 {
type Bytes = [u8; 8];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -85,7 +136,7 @@ impl<'a> ToBytes<'a> for u64 {
}
}
impl<'a> ToBytes<'a> for u32 {
impl ToBytes<'_> for u32 {
type Bytes = [u8; 4];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -93,6 +144,14 @@ impl<'a> ToBytes<'a> for u32 {
}
}
impl ToBytes<'_> for bool {
type Bytes = [u8; 1];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
Ok([*self as u8])
}
}
impl<'a, T: ToBytes<'a>> ToBytes<'a> for &'a T {
type Bytes = T::Bytes;
@@ -100,3 +159,26 @@ impl<'a, T: ToBytes<'a>> ToBytes<'a> for &'a T {
<T as ToBytes>::to_bytes(self)
}
}
impl<'a, T: ToBytes<'a>> ToBytes<'a> for Option<T> {
type Bytes = Vec<u8>;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
match self {
Some(x) => x.to_bytes().map(|x| x.as_ref().to_vec()),
None => Ok(vec![]),
}
}
}
#[test]
fn test() {
use extism_convert::{Json, ToBytes};
use serde::Serialize;
#[derive(ToBytes, Serialize)]
#[encoding(Json)]
struct Struct {
hello: String,
}
}

View File

@@ -1,16 +0,0 @@
FLAGS=`pkg-config --cflags --libs jsoncpp gtest` -lextism -lpthread
build-example:
$(CXX) -std=c++14 -o example -I. example.cpp $(FLAGS)
.PHONY: example
example: build-example
./example
build-test:
$(CXX) -std=c++14 -o test/test -I. test/test.cpp $(FLAGS)
.PHONY: test
test: build-test
cd test && ./test

View File

@@ -1,44 +0,0 @@
#define EXTISM_NO_JSON
#include "extism.hpp"
#include <cstring>
#include <fstream>
#include <iostream>
using namespace extism;
std::vector<uint8_t> read(const char *filename) {
std::ifstream file(filename, std::ios::binary);
return std::vector<uint8_t>((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
}
int main(int argc, char *argv[]) {
auto wasm = read("../wasm/code-functions.wasm");
std::string tmp = "Testing";
// A lambda can be used as a host function
auto hello_world = [&tmp](CurrentPlugin plugin,
const std::vector<Val> &inputs,
std::vector<Val> &outputs, void *user_data) {
std::cout << "Hello from C++" << std::endl;
std::cout << (const char *)user_data << std::endl;
std::cout << tmp << std::endl;
outputs[0].v = inputs[0].v;
};
std::vector<Function> functions = {
Function("hello_world", {ValType::I64}, {ValType::I64}, hello_world,
(void *)"Hello again!",
[](void *x) { std::cout << "Free user data" << std::endl; }),
};
Plugin plugin(wasm, true, functions);
const char *input = argc > 1 ? argv[1] : "this is a test";
ExtismSize length = strlen(input);
extism::Buffer output = plugin.call("count_vowels", (uint8_t *)input, length);
std::cout << (char *)output.data << std::endl;
return 0;
}

View File

@@ -1,458 +0,0 @@
#pragma once
#include <cstring>
#include <functional>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
#ifndef EXTISM_NO_JSON
#if __has_include(<jsoncpp/json/json.h>)
#include <jsoncpp/json/json.h>
#else
#include <json/json.h>
#endif
#endif // EXTISM_NO_JSON
extern "C" {
#include <extism.h>
}
namespace extism {
typedef std::map<std::string, std::string> Config;
template <typename T> class ManifestKey {
bool is_set = false;
public:
T value;
ManifestKey(T x, bool is_set = false) : is_set(is_set) { value = x; }
void set(T x) {
value = x;
is_set = true;
}
bool empty() const { return is_set == false; }
};
class Wasm {
std::string _path;
std::string _url;
// TODO: add base64 encoded raw data
ManifestKey<std::string> _hash =
ManifestKey<std::string>(std::string(), false);
public:
// Create Wasm pointing to a path
static Wasm path(std::string s, std::string hash = std::string()) {
Wasm w;
w._path = s;
if (!hash.empty()) {
w._hash.set(hash);
}
return w;
}
// Create Wasm pointing to a URL
static Wasm url(std::string s, std::string hash = std::string()) {
Wasm w;
w._url = s;
if (!hash.empty()) {
w._hash.set(hash);
}
return w;
}
#ifndef EXTISM_NO_JSON
Json::Value json() const {
Json::Value doc;
if (!this->_path.empty()) {
doc["path"] = this->_path;
} else if (!this->_url.empty()) {
doc["url"] = this->_url;
}
if (!this->_hash.empty()) {
doc["hash"] = this->_hash.value;
}
return doc;
}
#endif
};
class Manifest {
public:
Config config;
std::vector<Wasm> wasm;
ManifestKey<std::vector<std::string>> allowed_hosts;
ManifestKey<std::map<std::string, std::string>> allowed_paths;
ManifestKey<uint64_t> timeout_ms;
// Empty manifest
Manifest()
: timeout_ms(0, false), allowed_hosts(std::vector<std::string>(), false),
allowed_paths(std::map<std::string, std::string>(), false) {}
// Create manifest with a single Wasm from a path
static Manifest path(std::string s, std::string hash = std::string()) {
Manifest m;
m.add_wasm_path(s, hash);
return m;
}
// Create manifest with a single Wasm from a URL
static Manifest url(std::string s, std::string hash = std::string()) {
Manifest m;
m.add_wasm_url(s, hash);
return m;
}
#ifndef EXTISM_NO_JSON
std::string json() const {
Json::Value doc;
Json::Value wasm;
for (auto w : this->wasm) {
wasm.append(w.json());
}
doc["wasm"] = wasm;
if (!this->config.empty()) {
Json::Value conf;
for (auto k : this->config) {
conf[k.first] = k.second;
}
doc["config"] = conf;
}
if (!this->allowed_hosts.empty()) {
Json::Value h;
for (auto s : this->allowed_hosts.value) {
h.append(s);
}
doc["allowed_hosts"] = h;
}
if (!this->allowed_paths.empty()) {
Json::Value h;
for (auto k : this->allowed_paths.value) {
h[k.first] = k.second;
}
doc["allowed_paths"] = h;
}
if (!this->timeout_ms.empty()) {
doc["timeout_ms"] = Json::Value(this->timeout_ms.value);
}
Json::FastWriter writer;
return writer.write(doc);
}
#endif
// Add Wasm from path
void add_wasm_path(std::string s, std::string hash = std::string()) {
Wasm w = Wasm::path(s, hash);
this->wasm.push_back(w);
}
// Add Wasm from URL
void add_wasm_url(std::string u, std::string hash = std::string()) {
Wasm w = Wasm::url(u, hash);
this->wasm.push_back(w);
}
// Add host to allowed hosts
void allow_host(std::string host) {
if (this->allowed_hosts.empty()) {
this->allowed_hosts.set(std::vector<std::string>{});
}
this->allowed_hosts.value.push_back(host);
}
// Add path to allowed paths
void allow_path(std::string src, std::string dest = std::string()) {
if (this->allowed_paths.empty()) {
this->allowed_paths.set(std::map<std::string, std::string>{});
}
if (dest.empty()) {
dest = src;
}
this->allowed_paths.value[src] = dest;
}
// Set timeout
void set_timeout_ms(uint64_t ms) { this->timeout_ms = ms; }
// Set config key/value
void set_config(std::string k, std::string v) { this->config[k] = v; }
};
class Error : public std::runtime_error {
public:
Error(std::string msg) : std::runtime_error(msg) {}
};
class Buffer {
public:
Buffer(const uint8_t *ptr, ExtismSize len) : data(ptr), length(len) {}
const uint8_t *data;
ExtismSize length;
std::string string() { return (std::string)(*this); }
std::vector<uint8_t> vector() { return (std::vector<uint8_t>)(*this); }
operator std::string() { return std::string((const char *)data, length); }
operator std::vector<uint8_t>() {
return std::vector<uint8_t>(data, data + length);
}
};
typedef ExtismValType ValType;
typedef ExtismValUnion ValUnion;
typedef ExtismVal Val;
typedef uint64_t MemoryHandle;
class CurrentPlugin {
ExtismCurrentPlugin *pointer;
public:
CurrentPlugin(ExtismCurrentPlugin *p) : pointer(p) {}
uint8_t *memory() { return extism_current_plugin_memory(this->pointer); }
uint8_t *memory(MemoryHandle offs) { return this->memory() + offs; }
ExtismSize memoryLength(MemoryHandle offs) {
return extism_current_plugin_memory_length(this->pointer, offs);
}
MemoryHandle alloc(ExtismSize size) {
return extism_current_plugin_memory_alloc(this->pointer, size);
}
void free(MemoryHandle handle) {
extism_current_plugin_memory_free(this->pointer, handle);
}
void returnString(Val &output, const std::string &s) {
this->returnBytes(output, (const uint8_t *)s.c_str(), s.size());
}
void returnBytes(Val &output, const uint8_t *bytes, size_t len) {
auto offs = this->alloc(len);
memcpy(this->memory() + offs, bytes, len);
output.v.i64 = offs;
}
uint8_t *inputBytes(Val &inp, size_t *length = nullptr) {
if (inp.t != ValType::I64) {
return nullptr;
}
if (length != nullptr) {
*length = this->memoryLength(inp.v.i64);
}
return this->memory() + inp.v.i64;
}
std::string inputString(Val &inp) {
size_t length = 0;
char *buf = (char *)this->inputBytes(inp, &length);
return std::string(buf, length);
}
};
typedef std::function<void(CurrentPlugin, const std::vector<Val> &,
std::vector<Val> &, void *user_data)>
FunctionType;
struct UserData {
FunctionType func;
void *user_data = NULL;
std::function<void(void *)> free_user_data;
};
static void function_callback(ExtismCurrentPlugin *plugin,
const ExtismVal *inputs, ExtismSize n_inputs,
ExtismVal *outputs, ExtismSize n_outputs,
void *user_data) {
UserData *data = (UserData *)user_data;
const std::vector<Val> inp(inputs, inputs + n_inputs);
std::vector<Val> outp(outputs, outputs + n_outputs);
data->func(CurrentPlugin(plugin), inp, outp, data->user_data);
for (ExtismSize i = 0; i < n_outputs; i++) {
outputs[i] = outp[i];
}
}
static void free_user_data(void *user_data) {
UserData *data = (UserData *)user_data;
if (data->user_data != NULL && data->free_user_data != NULL) {
data->free_user_data(data->user_data);
}
}
class Function {
std::shared_ptr<ExtismFunction> func;
std::string name;
UserData user_data;
public:
Function(std::string name, const std::vector<ValType> inputs,
const std::vector<ValType> outputs, FunctionType f,
void *user_data = NULL, std::function<void(void *)> free = nullptr)
: name(name) {
this->user_data.func = f;
this->user_data.user_data = user_data;
this->user_data.free_user_data = free;
auto ptr = extism_function_new(
this->name.c_str(), inputs.data(), inputs.size(), outputs.data(),
outputs.size(), function_callback, &this->user_data, free_user_data);
this->func = std::shared_ptr<ExtismFunction>(ptr, extism_function_free);
}
void setNamespace(std::string s) {
extism_function_set_namespace(this->func.get(), s.c_str());
}
Function(const Function &f) { this->func = f.func; }
ExtismFunction *get() { return this->func.get(); }
};
class CancelHandle {
const ExtismCancelHandle *handle;
public:
CancelHandle(const ExtismCancelHandle *x) : handle(x){};
bool cancel() { return extism_plugin_cancel(this->handle); }
};
class Plugin {
std::vector<Function> functions;
public:
ExtismPlugin *plugin;
// Create a new plugin
Plugin(const uint8_t *wasm, ExtismSize length, bool with_wasi = false,
std::vector<Function> functions = std::vector<Function>())
: functions(functions) {
std::vector<const ExtismFunction *> ptrs;
for (auto i : this->functions) {
ptrs.push_back(i.get());
}
char *errmsg = nullptr;
this->plugin = extism_plugin_new(wasm, length, ptrs.data(), ptrs.size(),
with_wasi, &errmsg);
if (this->plugin == nullptr) {
std::string s(errmsg);
extism_plugin_new_error_free(errmsg);
throw Error(s);
}
}
Plugin(const std::string &str, bool with_wasi = false,
std::vector<Function> functions = {})
: Plugin((const uint8_t *)str.c_str(), str.size(), with_wasi, functions) {
}
Plugin(const std::vector<uint8_t> &data, bool with_wasi = false,
std::vector<Function> functions = {})
: Plugin(data.data(), data.size(), with_wasi, functions) {}
CancelHandle cancelHandle() {
return CancelHandle(extism_plugin_cancel_handle(this->plugin));
}
#ifndef EXTISM_NO_JSON
// Create a new plugin from Manifest
Plugin(const Manifest &manifest, bool with_wasi = false,
std::vector<Function> functions = {})
: Plugin(manifest.json().c_str(), with_wasi, functions) {}
~Plugin() {
extism_plugin_free(this->plugin);
this->plugin = nullptr;
}
void config(const Config &data) {
Json::Value conf;
for (auto k : data) {
conf[k.first] = k.second;
}
Json::FastWriter writer;
auto s = writer.write(conf);
this->config(s);
}
#endif
void config(const char *json, size_t length) {
bool b = extism_plugin_config(this->plugin, (const uint8_t *)json, length);
if (!b) {
const char *err = extism_plugin_error(this->plugin);
throw Error(err == nullptr ? "Unable to update plugin config" : err);
}
}
void config(const std::string &json) {
this->config(json.c_str(), json.size());
}
// Call a plugin
Buffer call(const std::string &func, const uint8_t *input,
ExtismSize input_length) const {
int32_t rc =
extism_plugin_call(this->plugin, func.c_str(), input, input_length);
if (rc != 0) {
const char *error = extism_plugin_error(this->plugin);
if (error == nullptr) {
throw Error("extism_call failed");
}
throw Error(error);
}
ExtismSize length = extism_plugin_output_length(this->plugin);
const uint8_t *ptr = extism_plugin_output_data(this->plugin);
return Buffer(ptr, length);
}
// Call a plugin function with std::vector<uint8_t> input
Buffer call(const std::string &func,
const std::vector<uint8_t> &input) const {
return this->call(func, input.data(), input.size());
}
// Call a plugin function with string input
Buffer call(const std::string &func,
const std::string &input = std::string()) const {
return this->call(func, (const uint8_t *)input.c_str(), input.size());
}
// Returns true if the specified function exists
bool functionExists(const std::string &func) const {
return extism_plugin_function_exists(this->plugin, func.c_str());
}
};
// Set global log file for plugins
inline bool setLogFile(const char *filename, const char *level) {
return extism_log_file(filename, level);
}
// Get libextism version
inline std::string version() { return std::string(extism_version()); }
} // namespace extism

View File

@@ -1,117 +0,0 @@
#include "../extism.hpp"
#include <fstream>
#include <thread>
#include <gtest/gtest.h>
std::vector<uint8_t> read(const char *filename) {
std::ifstream file(filename, std::ios::binary);
return std::vector<uint8_t>((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
}
const std::string code = "../../wasm/code.wasm";
namespace {
using namespace extism;
TEST(Plugin, Manifest) {
Manifest manifest = Manifest::path(code);
manifest.set_config("a", "1");
Plugin plugin(manifest);
Buffer buf = plugin.call("count_vowels", "this is a test");
ASSERT_EQ((std::string)buf, "{\"count\": 4}");
}
TEST(Plugin, BadManifest) {
Manifest manifest;
ASSERT_THROW(Plugin plugin(manifest), Error);
}
TEST(Plugin, Bytes) {
auto wasm = read(code.c_str());
ASSERT_NO_THROW(Plugin plugin(wasm));
Plugin plugin(wasm);
Buffer buf = plugin.call("count_vowels", "this is another test");
ASSERT_EQ(buf.string(), "{\"count\": 6}");
}
TEST(Plugin, UpdateConfig) {
auto wasm = read(code.c_str());
Plugin plugin(wasm);
Config config;
config["abc"] = "123";
ASSERT_NO_THROW(plugin.config(config));
}
TEST(Plugin, FunctionExists) {
auto wasm = read(code.c_str());
Plugin plugin(wasm);
ASSERT_FALSE(plugin.functionExists("bad_function"));
ASSERT_TRUE(plugin.functionExists("count_vowels"));
}
TEST(Plugin, HostFunction) {
auto wasm = read("../../wasm/code-functions.wasm");
auto t = std::vector<ValType>{ValType::I64};
Function hello_world =
Function("hello_world", t, t,
[](CurrentPlugin plugin, const std::vector<Val> &params,
std::vector<Val> &results, void *user_data) {
auto offs = plugin.alloc(4);
memcpy(plugin.memory() + offs, "test", 4);
results[0].v.i64 = (int64_t)offs;
});
auto functions = std::vector<Function>{
hello_world,
};
Plugin plugin(wasm, true, functions);
auto buf = plugin.call("count_vowels", "aaa");
ASSERT_EQ(buf.length, 4);
ASSERT_EQ((std::string)buf, "test");
}
void callThread(Plugin *plugin) {
auto buf = plugin->call("count_vowels", "aaa").string();
ASSERT_EQ(buf.size(), 10);
ASSERT_EQ(buf, "testing123");
}
TEST(Plugin, MultipleThreads) {
auto wasm = read("../../wasm/code-functions.wasm");
auto t = std::vector<ValType>{ValType::I64};
Function hello_world =
Function("hello_world", t, t,
[](CurrentPlugin plugin, const std::vector<Val> &params,
std::vector<Val> &results, void *user_data) {
auto offs = plugin.alloc(10);
memcpy(plugin.memory() + offs, "testing123", 10);
results[0].v.i64 = (int64_t)offs;
});
auto functions = std::vector<Function>{
hello_world,
};
Plugin plugin(wasm, true, functions);
std::vector<std::thread> threads;
for (int i = 0; i < 3; i++) {
threads.push_back(std::thread(callThread, &plugin));
}
for (auto &th : threads) {
th.join();
}
}
}; // namespace
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

7
d/.gitignore vendored
View File

@@ -1,7 +0,0 @@
# Generated by host system's C preprocessor
# See https://dlang.org/spec/importc.html#manual-cpp
runtime.i
docs.json
extism-test-*
*.lst

View File

@@ -1,4 +0,0 @@
# D Host SDK
Development of this library has moved to [this repo](https://github.com/extism/d-sdk#readme).

View File

@@ -1,17 +0,0 @@
.dub
docs.json
__dummy.html
docs/
/extism_hello
/hello
hello.so
hello.dylib
hello.dll
hello.a
hello.lib
hello-test-*
*.exe
*.pdb
*.o
*.obj
*.lst

View File

@@ -1,15 +0,0 @@
{
"name": "hello",
"description": "A minimal Extism usage example",
"license": "BSD-3-Clause",
"authors": [
"Chance Snow <git@chancesnow.me>",
"Extism contributors"
],
"copyright": "Copyright © 2023, Extism contributors",
"dependencies": {
"extism": {
"path": "../../../"
}
}
}

View File

@@ -1,33 +0,0 @@
import std.conv: castFrom, to;
import std.file;
import std.functional: toDelegate;
import std.stdio;
import std.string: representation;
import std.typecons : Yes;
import extism;
void main() {
auto wasm = cast(ubyte[]) read("wasm/code-functions.wasm");
// FIXME: Creating the plugin results in EXC_BAD_ACCESS (segfault?) from `extism_plugin_new`
auto plugin = new Plugin(wasm, [
Function!string(
"hello_world", /* Inputs */ [ValType.i64], /* Outputs */ [ValType.i64], toDelegate(&helloWorld), "Hello, again!"
),
], Yes.withWasi);
auto input = "aeiou";
plugin.call("count_vowels", cast(ubyte[]) input.representation);
writeln(plugin.outputData);
}
///
void helloWorld(CurrentPlugin plugin, const Val[] inputs, Val[] outputs, void *data) {
writeln("Hello from D!");
writeln(data);
ExtismSize ptr_offs = inputs[0].v.i64;
auto buf = plugin.memory(ptr_offs);
writeln(buf);
outputs[0].v.i64 = inputs[0].v.i64;
}

View File

@@ -1,258 +0,0 @@
module extism;
import std.conv: castFrom, to;
import std.meta: Alias;
import std.string: fromStringz, toStringz;
import runtime;
/// A list of all possible value types in WebAssembly.
enum ValType {
i32 = I32,
i64 = I64,
f32 = F32,
f64 = F64,
v128 = V128,
funcRef = FuncRef,
externRef = ExternRef,
}
// Opaque Pointers
///
alias CancelHandle = Alias!(void*);
///
alias CurrentPlugin = Alias!(void*);
///
alias ExtismSize = ulong;
/// A union type for host function argument/return values.
union ValUnion {
///
int i32;
///
long i64;
///
float f32;
///
double f64;
}
/// Holds the type and value of a function argument/return.
struct Val {
///
ValType t;
///
ValUnion v;
}
/// Host function signature.
///
/// Used to register host functions with plugins.
/// Params:
/// plugin: the currently executing plugin from within a host function
/// inputs: argument values
/// outputs: return values
/// data: user data associated with the host function
alias FunctionType = void delegate(
CurrentPlugin plugin, const Val[] inputs, Val[] outputs, void* data
);
/// Returns: A slice of an allocated memory block of the currently running plugin.
ubyte[] memory(CurrentPlugin plugin, ulong n) {
auto length = extism_current_plugin_memory_length(cast(ExtismCurrentPlugin*) plugin, n);
return extism_current_plugin_memory(cast(ExtismCurrentPlugin*) plugin)[n .. (n + length)];
}
/// Allocate a memory block in the currently running plugin.
ulong memoryAlloc(CurrentPlugin plugin, ulong n) {
return extism_current_plugin_memory_alloc(cast(ExtismCurrentPlugin*) plugin, n);
}
/// Free an allocated memory block.
void memoryFree(CurrentPlugin plugin, ulong ptr) {
extism_current_plugin_memory_free(cast(ExtismCurrentPlugin*) plugin, ptr);
}
/// A host function, where `T` is the type of its user data.
struct Function(T) {
/// Managed pointer.
ExtismFunction* func;
alias func this;
private string _namespace = null;
/// Create a new host function.
/// Params:
/// name: function name, this should be valid UTF-8
/// inputs: argument types
/// outputs: return types
/// func: the function to call
/// userData: a pointer that will be passed to the function when it's called. This value should live as long as the function exists.
/// freeUserData: a callback to release the `userData`` value when the resulting `Function` is freed.
this(
string name, const ValType[] inputs, const ValType[] outputs, FunctionType func,
T userData, void function(T userData) freeUserData = null
) {
import std.functional: toDelegate;
// Bind the given host function with C linkage
auto funcClosure = ((
ExtismCurrentPlugin* plugin,
const ExtismVal* inputs, ulong numInputs, ExtismVal* outputs, ulong numOutputs,
void* data
) {
func(plugin, (cast(const Val*) inputs)[0 .. numInputs], (cast(Val*) outputs)[0 .. numOutputs], data);
}).toDelegate.bindDelegate;
// Bind the `freeUserData` function with C linkage
auto freeUserDataHandler = freeUserData is null ? null : ((void* userDataPtr) {
if (userDataPtr is null) return;
freeUserData((&userDataPtr).to!T);
}).toDelegate.bindDelegate;
this.func = extism_function_new(
name.toStringz,// See https://dlang.org/spec/importc.html#enums
// See https://forum.dlang.org/post/qmidcpaxctbuphcyvkdc@forum.dlang.org
castFrom!(const(ValType)*)
.to!(typeof(ExtismVal.t)*)(inputs.ptr), inputs.length,
castFrom!(const(ValType)*).to!(typeof(ExtismVal.t)*)(outputs.ptr), outputs.length,
funcClosure,
&userData,
freeUserDataHandler,
);
}
~this() {
extism_function_free(func);
}
/// Get the namespace of this function.
string namespace() {
return this._namespace;
}
/// Set the namespace of this function.
void namespace(string value) {
this._namespace = value;
extism_function_set_namespace(func, value.toStringz);
}
}
///
struct Plugin {
import std.uuid: UUID;
/// Managed pointer.
ExtismPlugin* plugin;
alias plugin this;
/// Create a new plugin.
/// Params:
/// wasm: is a WASM module (wat or wasm) or a JSON encoded manifest
/// functions: is an array of ExtismFunction*
/// withWasi: enables/disables WASI
/// Throws: `Exception` if the plugin could not be created.
this(const ubyte[] wasm, const(ExtismFunction)*[] functions, bool withWasi = false) {
char* errorMsgPtr = null;
plugin = extism_plugin_new(
wasm.ptr, wasm.length, cast(ExtismFunction**) functions.ptr, functions.length, withWasi, &errorMsgPtr
);
// See https://github.com/extism/extism/blob/ddcbeec3debe787293a9957c8be88f80a64b7c22/c/main.c#L67
// Instead of terminating the host process, throw.
if (plugin !is null)
return;
auto errorMsg = errorMsgPtr.fromStringz.idup;
extism_plugin_new_error_free(errorMsgPtr);
// TODO: Subclass `Exception` for better error handling
throw new Exception(errorMsg);
}
~this() {
extism_plugin_free(plugin);
}
/// Get a plugin's ID.
UUID id() {
return UUID(extism_plugin_id(plugin)[0 .. 16]);
}
/// Get the error associated with this `Plugin`.
string error() {
return extism_error(plugin).fromStringz.idup;
}
/// Update plugin config values, this will merge with the existing values.
bool config(ubyte[] json) {
return extism_plugin_config(plugin, json.ptr, json.length);
}
/// See_Also: `cancel`
const(CancelHandle) cancelHandle() {
return extism_plugin_cancel_handle(plugin);
}
/// Cancel a running plugin.
/// See_Also: `cancelHandle`
bool cancel(const CancelHandle handle) {
return extism_plugin_cancel(cast(ExtismCancelHandle*) handle);
}
/// Returns: Whether a function with `name` exists.
bool functionExists(string name) {
return extism_plugin_function_exists(plugin, name.toStringz);
}
/// Call a function.
/// Params:
/// funcName: is the function to call
/// data: is the input data
void call(string funcName, ubyte[] data = null) {
// Returns `0` if the call was successful, otherwise `-1`.
if (extism_plugin_call(plugin, funcName.toStringz, data.ptr, data.length) != 0)
throw new Exception(this.error);
}
/// Get the plugin's output data.
///
/// Note: This copies the data into a managed buffer.
/// Remarks: Use `outputData.length` to retrieve size of plugin output.
ubyte[] outputData() {
import std.algorithm: copy;
auto outputLength = extism_plugin_output_length(plugin);
auto outputData = extism_plugin_output_data(plugin)[0 .. outputLength];
auto buffer = new ubyte[outputLength];
assert(
outputData.copy(buffer).length == 0,
"Output data was not completely copied into buffer, i.e. buffer was not filled."
);
return buffer;
}
}
/// Get the error associated with a `Context` or `Plugin`, if plugin is -1 then the context error will be returned.
/// Set log file and level.
bool setLogFile(string filename, string logLevel) {
return extism_log_file(filename.toStringz, logLevel.toStringz);
}
/// Get the Extism version string.
string version_() {
return extism_version().fromStringz.idup;
}
import std.traits: isDelegate;
/// Transform the given delegate into a static function pointer with C linkage.
/// See_Also: <a href="https://stackoverflow.com/a/22845722/1363247">stackoverflow.com/a/22845722/1363247</a>
package auto bindDelegate(Func)(Func f) if (isDelegate!Func) {
import std.traits: ParameterTypeTuple, ReturnType;
static Func delegate_;
delegate_ = f;
extern (C) static ReturnType!Func func(ParameterTypeTuple!Func args) {
return delegate_(args);
}
return &func;
}

View File

@@ -1 +0,0 @@
#include "runtime/extism.h"

View File

@@ -1,37 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33110.190
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.Sdk", "src\Extism.Sdk\Extism.Sdk.csproj", "{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.Sdk.Tests", "test\Extism.Sdk\Extism.Sdk.Tests.csproj", "{DB440D61-C781-4C59-9223-9A79CC9FB4E7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.Sdk.Sample", "samples\Extism.Sdk.Sample\Extism.Sdk.Sample.csproj", "{2232E572-E8BA-46A1-AF31-E4168960DB75}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Release|Any CPU.Build.0 = Release|Any CPU
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Release|Any CPU.Build.0 = Release|Any CPU
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2B6BF267-F2A5-4CB5-8DFD-F11CC8787E6B}
EndGlobalSection
EndGlobal

View File

@@ -1,4 +0,0 @@
# Dotnet Host SDK
This contains the `0.x` version of the SDK. Development of this library has moved to [this repo](https://github.com/extism/dotnet-sdk#readme).

View File

@@ -1,66 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.runtime.linux-arm64", "Extism.runtime.linux-arm64.csproj", "{F1CF6818-43C4-4CD6-A3AD-748EFC83C21B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.runtime.linux-musl-arm64", "Extism.runtime.linux-musl-arm64.csproj", "{2E563F73-9FD5-42B2-9368-12BBF5819148}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.runtime.linux-x64", "Extism.runtime.linux-x64.csproj", "{A2E24D65-8AE2-4C09-82CB-5AEBA0539973}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.runtime.osx-arm64", "Extism.runtime.osx-arm64.csproj", "{66461A9C-140C-48C1-B658-BE540220460D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.runtime.osx-x64", "Extism.runtime.osx-x64.csproj", "{BE23CF82-F668-4166-8579-0FF2B20EA095}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.runtime.win-x64", "Extism.runtime.win-x64.csproj", "{639F9EFE-AC2A-43A7-A9BB-EDAEB306455F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.runtime.all", "Extism.runtime.all.csproj", "{88DF54A7-845B-409D-93FE-64CF2864FFDE}"
ProjectSection(ProjectDependencies) = postProject
{2E563F73-9FD5-42B2-9368-12BBF5819148} = {2E563F73-9FD5-42B2-9368-12BBF5819148}
{639F9EFE-AC2A-43A7-A9BB-EDAEB306455F} = {639F9EFE-AC2A-43A7-A9BB-EDAEB306455F}
{66461A9C-140C-48C1-B658-BE540220460D} = {66461A9C-140C-48C1-B658-BE540220460D}
{A2E24D65-8AE2-4C09-82CB-5AEBA0539973} = {A2E24D65-8AE2-4C09-82CB-5AEBA0539973}
{BE23CF82-F668-4166-8579-0FF2B20EA095} = {BE23CF82-F668-4166-8579-0FF2B20EA095}
{F1CF6818-43C4-4CD6-A3AD-748EFC83C21B} = {F1CF6818-43C4-4CD6-A3AD-748EFC83C21B}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F1CF6818-43C4-4CD6-A3AD-748EFC83C21B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F1CF6818-43C4-4CD6-A3AD-748EFC83C21B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F1CF6818-43C4-4CD6-A3AD-748EFC83C21B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F1CF6818-43C4-4CD6-A3AD-748EFC83C21B}.Release|Any CPU.Build.0 = Release|Any CPU
{2E563F73-9FD5-42B2-9368-12BBF5819148}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E563F73-9FD5-42B2-9368-12BBF5819148}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E563F73-9FD5-42B2-9368-12BBF5819148}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E563F73-9FD5-42B2-9368-12BBF5819148}.Release|Any CPU.Build.0 = Release|Any CPU
{A2E24D65-8AE2-4C09-82CB-5AEBA0539973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2E24D65-8AE2-4C09-82CB-5AEBA0539973}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2E24D65-8AE2-4C09-82CB-5AEBA0539973}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2E24D65-8AE2-4C09-82CB-5AEBA0539973}.Release|Any CPU.Build.0 = Release|Any CPU
{66461A9C-140C-48C1-B658-BE540220460D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66461A9C-140C-48C1-B658-BE540220460D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66461A9C-140C-48C1-B658-BE540220460D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66461A9C-140C-48C1-B658-BE540220460D}.Release|Any CPU.Build.0 = Release|Any CPU
{BE23CF82-F668-4166-8579-0FF2B20EA095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BE23CF82-F668-4166-8579-0FF2B20EA095}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BE23CF82-F668-4166-8579-0FF2B20EA095}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BE23CF82-F668-4166-8579-0FF2B20EA095}.Release|Any CPU.Build.0 = Release|Any CPU
{639F9EFE-AC2A-43A7-A9BB-EDAEB306455F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{639F9EFE-AC2A-43A7-A9BB-EDAEB306455F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{639F9EFE-AC2A-43A7-A9BB-EDAEB306455F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{639F9EFE-AC2A-43A7-A9BB-EDAEB306455F}.Release|Any CPU.Build.0 = Release|Any CPU
{88DF54A7-845B-409D-93FE-64CF2864FFDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88DF54A7-845B-409D-93FE-64CF2864FFDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88DF54A7-845B-409D-93FE-64CF2864FFDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88DF54A7-845B-409D-93FE-64CF2864FFDE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -1 +0,0 @@
win-x64.dll

View File

@@ -1,29 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<None Include="..\..\..\wasm\code.wasm" Link="code.wasm">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\..\..\wasm\code-functions.wasm" Link="code-functions.wasm">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Extism.runtime.win-x64" Version="0.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Extism.Sdk\Extism.Sdk.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,38 +0,0 @@
using Extism.Sdk;
using Extism.Sdk.Native;
using System.Runtime.InteropServices;
using System.Text;
var userData = Marshal.StringToHGlobalAnsi("Hello again!");
using var helloWorld = new HostFunction(
"hello_world",
"env",
new[] { ExtismValType.I64 },
new[] { ExtismValType.I64 },
userData,
HelloWorld);
void HelloWorld(CurrentPlugin plugin, Span<ExtismVal> inputs, Span<ExtismVal> outputs, nint data)
{
Console.WriteLine("Hello from .NET!");
var text = Marshal.PtrToStringAnsi(data);
Console.WriteLine(text);
var input = plugin.ReadString(new nint(inputs[0].v.i64));
Console.WriteLine($"Input: {input}");
outputs[0].v.i64 = plugin.WriteString(input);
}
var wasm = File.ReadAllBytes("./code-functions.wasm");
using var plugin = new Plugin(wasm, new[] { helloWorld }, withWasi: true);
var output = Encoding.UTF8.GetString(
plugin.CallFunction("count_vowels", Encoding.UTF8.GetBytes("Hello World!"))
);
Console.WriteLine($"Output: {output}");

View File

@@ -1,5 +0,0 @@
## Example 1
This example shows how you can use the library in the most basic way.
It loads up the sample wasm plugin and lets you to pass inputs to it and show the ouput.
**Please note that on Windows you have to manually copy the `extism.dll` file to the ouput directory.**

View File

@@ -1,24 +0,0 @@
<!-- Recommended practices for publishing nuget packages from: https://devblogs.microsoft.com/dotnet/producing-packages-with-source-link/ -->
<Project>
<PropertyGroup>
<!-- Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<!-- Embed source files that are not tracked by the source control manager in the PDB -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- Recommended: Embed symbols containing Source Link in the main file (exe/dll) -->
<DebugType>embedded</DebugType>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
</Project>

View File

@@ -1,138 +0,0 @@
using Extism.Sdk.Native;
using System.Text;
namespace Extism.Sdk
{
/// <summary>
/// Represents the current plugin. Can only be used within <see cref="HostFunction"/>s.
/// </summary>
public class CurrentPlugin
{
internal CurrentPlugin(nint nativeHandle)
{
NativeHandle = nativeHandle;
}
internal nint NativeHandle { get; }
/// <summary>
/// Returns a pointer to the memory of the currently running plugin.
/// NOTE: this should only be called from host functions.
/// </summary>
/// <returns></returns>
public nint GetMemory()
{
return LibExtism.extism_current_plugin_memory(NativeHandle);
}
/// <summary>
/// Reads a string from a memory block using UTF8.
/// </summary>
/// <param name="pointer"></param>
/// <returns></returns>
public string ReadString(nint pointer)
{
return ReadString(pointer, Encoding.UTF8);
}
/// <summary>
/// Reads a string form a memory block.
/// </summary>
/// <param name="pointer"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public string ReadString(nint pointer, Encoding encoding)
{
var buffer = ReadBytes(pointer);
return encoding.GetString(buffer);
}
/// <summary>
/// Returns a span of bytes for a given block.
/// </summary>
/// <param name="pointer"></param>
/// <returns></returns>
public unsafe Span<byte> ReadBytes(nint pointer)
{
var mem = GetMemory();
var length = (int)BlockLength(pointer);
var ptr = (byte*)mem + pointer;
return new Span<byte>(ptr, length);
}
/// <summary>
/// Writes a string into the current plugin memory using UTF-8 encoding and returns the pointer of the block.
/// </summary>
/// <param name="value"></param>
public nint WriteString(string value)
=> WriteString(value, Encoding.UTF8);
/// <summary>
/// Writes a string into the current plugin memory and returns the pointer of the block.
/// </summary>
/// <param name="value"></param>
/// <param name="encoding"></param>
public nint WriteString(string value, Encoding encoding)
{
var bytes = encoding.GetBytes(value);
var pointer = AllocateBlock(bytes.Length);
WriteBytes(pointer, bytes);
return pointer;
}
/// <summary>
/// Writes a byte array into a block of memory.
/// </summary>
/// <param name="pointer"></param>
/// <param name="bytes"></param>
public unsafe void WriteBytes(nint pointer, Span<byte> bytes)
{
var length = BlockLength(pointer);
if (length < bytes.Length)
{
throw new InvalidOperationException("Destination block length is less than source block length.");
}
var mem = GetMemory();
var ptr = (void*)(mem + pointer);
var destination = new Span<byte>(ptr, bytes.Length);
bytes.CopyTo(destination);
}
/// <summary>
/// Frees a block of memory belonging to the current plugin.
/// </summary>
/// <param name="pointer"></param>
public void FreeBlock(nint pointer)
{
LibExtism.extism_current_plugin_memory_free(NativeHandle, pointer);
}
/// <summary>
/// Allocate a memory block in the currently running plugin.
///
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
public nint AllocateBlock(long length)
{
return LibExtism.extism_current_plugin_memory_alloc(NativeHandle, length);
}
/// <summary>
/// Get the length of an allocated block.
/// NOTE: this should only be called from host functions.
/// </summary>
/// <param name="pointer"></param>
/// <returns></returns>
public long BlockLength(nint pointer)
{
return LibExtism.extism_current_plugin_memory_length(NativeHandle, pointer);
}
}
}

View File

@@ -1,28 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<LangVersion>10</LangVersion>
</PropertyGroup>
<PropertyGroup>
<PackageId>Extism.Sdk</PackageId>
<Version>0.7.0</Version>
<Authors>Extism Contributors</Authors>
<Description>Extism SDK that allows hosting Extism plugins in .NET apps.</Description>
<Tags>extism, wasm, plugin</Tags>
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@@ -1,40 +0,0 @@
namespace Extism.Sdk.Native;
using System;
/// <summary>
/// Represents errors that occur during calling Extism functions.
/// </summary>
public class ExtismException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="ExtismException"/> class.
/// </summary>
public ExtismException()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExtismException"/> class with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error .</param>
public ExtismException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExtismException"/> class
/// with a specified error message and a reference to the inner exception
/// that is the cause of this exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="innerException">
/// The exception that is the cause of the current exception, or a null reference
/// (Nothing in Visual Basic) if no inner exception is specified.
/// </param>
public ExtismException(string message, Exception innerException)
: base(message, innerException)
{
}
}

View File

@@ -1,146 +0,0 @@
using Extism.Sdk.Native;
using System.Diagnostics.CodeAnalysis;
namespace Extism.Sdk
{
/// <summary>
/// A host function signature.
/// </summary>
/// <param name="plugin">Plugin Index</param>
/// <param name="inputs">Input parameters</param>
/// <param name="outputs">Output parameters, the host function can change this.</param>
/// <param name="userData">A data passed in during Host Function creation.</param>
public delegate void ExtismFunction(CurrentPlugin plugin, Span<ExtismVal> inputs, Span<ExtismVal> outputs, IntPtr userData);
/// <summary>
/// A function provided by the host that plugins can call.
/// </summary>
public class HostFunction : IDisposable
{
private const int DisposedMarker = 1;
private int _disposed;
/// <summary>
/// Registers a Host Function.
/// </summary>
/// <param name="functionName">The literal name of the function, how it would be called from a <see cref="Plugin"/>.</param>
/// <param name="inputTypes">The types of the input arguments/parameters the <see cref="Plugin"/> caller will provide.</param>
/// <param name="outputTypes">The types of the output returned from the host function to the <see cref="Plugin"/>.</param>
/// <param name="userData">An opaque pointer to an object from the host, accessible to the <see cref="Plugin"/>.
/// NOTE: it is the shared responsibility of the host and <see cref="Plugin"/> to cast/dereference this value properly.</param>
/// <param name="hostFunction"></param>
public HostFunction(
string functionName,
Span<ExtismValType> inputTypes,
Span<ExtismValType> outputTypes,
IntPtr userData,
ExtismFunction hostFunction) :
this(functionName, "", inputTypes, outputTypes, userData, hostFunction)
{
}
/// <summary>
/// Registers a Host Function.
/// </summary>
/// <param name="functionName">The literal name of the function, how it would be called from a <see cref="Plugin"/>.</param>
/// <param name="namespace">Function namespace.</param>
/// <param name="inputTypes">The types of the input arguments/parameters the <see cref="Plugin"/> caller will provide.</param>
/// <param name="outputTypes">The types of the output returned from the host function to the <see cref="Plugin"/>.</param>
/// <param name="userData">An opaque pointer to an object from the host, accessible to the <see cref="Plugin"/>.
/// NOTE: it is the shared responsibility of the host and <see cref="Plugin"/> to cast/dereference this value properly.</param>
/// <param name="hostFunction"></param>
unsafe public HostFunction(
string functionName,
string @namespace,
Span<ExtismValType> inputTypes,
Span<ExtismValType> outputTypes,
IntPtr userData,
ExtismFunction hostFunction)
{
fixed (ExtismValType* inputs = inputTypes)
fixed (ExtismValType* outputs = outputTypes)
{
NativeHandle = LibExtism.extism_function_new(functionName, inputs, inputTypes.Length, outputs, outputTypes.Length, CallbackImpl, userData, IntPtr.Zero);
}
if (!string.IsNullOrEmpty(@namespace))
{
LibExtism.extism_function_set_namespace(NativeHandle, @namespace);
}
void CallbackImpl(
nint plugin,
ExtismVal* inputsPtr,
uint n_inputs,
ExtismVal* outputsPtr,
uint n_outputs,
IntPtr data)
{
var outputs = new Span<ExtismVal>(outputsPtr, (int)n_outputs);
var inputs = new Span<ExtismVal>(inputsPtr, (int)n_inputs);
hostFunction(new CurrentPlugin(plugin), inputs, outputs, data);
}
}
internal IntPtr NativeHandle { get; }
/// <summary>
/// Frees all resources held by this Host Function.
/// </summary>
public void Dispose()
{
if (Interlocked.Exchange(ref _disposed, DisposedMarker) == DisposedMarker)
{
// Already disposed.
return;
}
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Throw an appropriate exception if the Host Function has been disposed.
/// </summary>
/// <exception cref="ObjectDisposedException"></exception>
protected void CheckNotDisposed()
{
Interlocked.MemoryBarrier();
if (_disposed == DisposedMarker)
{
ThrowDisposedException();
}
}
[DoesNotReturn]
private static void ThrowDisposedException()
{
throw new ObjectDisposedException(nameof(HostFunction));
}
/// <summary>
/// Frees all resources held by this Host Function.
/// </summary>
unsafe protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free up any managed resources here
}
// Free up unmanaged resources
LibExtism.extism_function_free(NativeHandle);
}
/// <summary>
/// Destructs the current Host Function and frees all resources used by it.
/// </summary>
~HostFunction()
{
Dispose(false);
}
}
}

View File

@@ -1,302 +0,0 @@
using System.Runtime.InteropServices;
namespace Extism.Sdk.Native;
/// <summary>
/// A union type for host function argument/return values.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct ExtismValUnion
{
/// <summary>
/// Set this for 32 bit integers
/// </summary>
[FieldOffset(0)]
public int i32;
/// <summary>
/// Set this for 64 bit integers
/// </summary>
[FieldOffset(0)]
public long i64;
/// <summary>
/// Set this for 32 bit floats
/// </summary>
[FieldOffset(0)]
public float f32;
/// <summary>
/// Set this for 64 bit floats
/// </summary>
[FieldOffset(0)]
public double f64;
}
/// <summary>
/// Represents Wasm data types that Extism can understand
/// </summary>
public enum ExtismValType : byte
{
/// <summary>
/// Signed 32 bit integer. Equivalent of <see cref="int"/> or <see cref="uint"/>
/// </summary>
I32,
/// <summary>
/// Signed 64 bit integer. Equivalent of <see cref="long"/> or <see cref="ulong"/>
/// </summary>
I64,
/// <summary>
/// Floating point 32 bit integer. Equivalent of <see cref="float"/>
/// </summary>
F32,
/// <summary>
/// Floating point 64 bit integer. Equivalent of <see cref="double"/>
/// </summary>
F64,
/// <summary>
/// A 128 bit number.
/// </summary>
V128,
/// <summary>
/// A reference to opaque data in the Wasm instance.
/// </summary>
FuncRef,
/// <summary>
/// A reference to opaque data in the Wasm instance.
/// </summary>
ExternRef
}
/// <summary>
/// `ExtismVal` holds the type and value of a function argument/return
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ExtismVal
{
/// <summary>
/// The type for the argument
/// </summary>
public ExtismValType t;
/// <summary>
/// The value for the argument
/// </summary>
public ExtismValUnion v;
}
/// <summary>
/// Functions exposed by the native Extism library.
/// </summary>
internal static class LibExtism
{
/// <summary>
/// An Extism Plugin
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct ExtismPlugin { }
/// <summary>
/// Host function signature
/// </summary>
/// <param name="plugin"></param>
/// <param name="inputs"></param>
/// <param name="n_inputs"></param>
/// <param name="outputs"></param>
/// <param name="n_outputs"></param>
/// <param name="data"></param>
unsafe internal delegate void InternalExtismFunction(nint plugin, ExtismVal* inputs, uint n_inputs, ExtismVal* outputs, uint n_outputs, IntPtr data);
/// <summary>
/// Returns a pointer to the memory of the currently running plugin.
/// NOTE: this should only be called from host functions.
/// </summary>
/// <param name="plugin"></param>
/// <returns></returns>
[DllImport("extism", EntryPoint = "extism_current_plugin_memory")]
internal static extern IntPtr extism_current_plugin_memory(nint plugin);
/// <summary>
/// Allocate a memory block in the currently running plugin
/// </summary>
/// <param name="plugin"></param>
/// <param name="n"></param>
/// <returns></returns>
[DllImport("extism", EntryPoint = "extism_current_plugin_memory_alloc")]
internal static extern IntPtr extism_current_plugin_memory_alloc(nint plugin, long n);
/// <summary>
/// Get the length of an allocated block.
/// NOTE: this should only be called from host functions.
/// </summary>
/// <param name="plugin"></param>
/// <param name="n"></param>
/// <returns></returns>
[DllImport("extism", EntryPoint = "extism_current_plugin_memory_length")]
internal static extern long extism_current_plugin_memory_length(nint plugin, long n);
/// <summary>
/// Get the length of an allocated block.
/// NOTE: this should only be called from host functions.
/// </summary>
/// <param name="plugin"></param>
/// <param name="ptr"></param>
[DllImport("extism", EntryPoint = "extism_current_plugin_memory_free")]
internal static extern void extism_current_plugin_memory_free(nint plugin, IntPtr ptr);
/// <summary>
/// Create a new host function.
/// </summary>
/// <param name="name">function name, this should be valid UTF-8</param>
/// <param name="inputs">argument types</param>
/// <param name="nInputs">number of argument types</param>
/// <param name="outputs">return types</param>
/// <param name="nOutputs">number of return types</param>
/// <param name="func">the function to call</param>
/// <param name="userData">a pointer that will be passed to the function when it's called this value should live as long as the function exists</param>
/// <param name="freeUserData">a callback to release the `user_data` value when the resulting `ExtismFunction` is freed.</param>
/// <returns></returns>
[DllImport("extism", EntryPoint = "extism_function_new")]
unsafe internal static extern IntPtr extism_function_new(string name, ExtismValType* inputs, long nInputs, ExtismValType* outputs, long nOutputs, InternalExtismFunction func, IntPtr userData, IntPtr freeUserData);
/// <summary>
/// Set the namespace of an <see cref="ExtismFunction"/>
/// </summary>
/// <param name="ptr"></param>
/// <param name="namespace"></param>
[DllImport("extism", EntryPoint = "extism_function_set_namespace")]
internal static extern void extism_function_set_namespace(IntPtr ptr, string @namespace);
/// <summary>
/// Free an <see cref="ExtismFunction"/>
/// </summary>
/// <param name="ptr"></param>
[DllImport("extism", EntryPoint = "extism_function_free")]
internal static extern void extism_function_free(IntPtr ptr);
/// <summary>
/// Load a WASM plugin.
/// </summary>
/// <param name="wasm">A WASM module (wat or wasm) or a JSON encoded manifest.</param>
/// <param name="wasmSize">The length of the `wasm` parameter.</param>
/// <param name="functions">Array of host function pointers.</param>
/// <param name="nFunctions">Number of host functions.</param>
/// <param name="withWasi">Enables/disables WASI.</param>
/// <returns></returns>
[DllImport("extism")]
unsafe internal static extern ExtismPlugin* extism_plugin_new(byte* wasm, int wasmSize, IntPtr* functions, int nFunctions, bool withWasi, IntPtr* errmsg);
/// <summary>
/// Remove a plugin from the registry and free associated memory.
/// </summary>
/// <param name="plugin">Pointer to the plugin you want to free.</param>
[DllImport("extism")]
unsafe internal static extern void extism_plugin_free(ExtismPlugin* plugin);
/// <summary>
/// Update plugin config values, this will merge with the existing values.
/// </summary>
/// <param name="plugin">Pointer to the plugin you want to update the configurations for.</param>
/// <param name="json">The configuration JSON encoded in UTF8.</param>
/// <param name="jsonLength">The length of the `json` parameter.</param>
/// <returns></returns>
[DllImport("extism")]
unsafe internal static extern bool extism_plugin_config(ExtismPlugin* plugin, byte* json, int jsonLength);
/// <summary>
/// Returns true if funcName exists.
/// </summary>
/// <param name="plugin"></param>
/// <param name="funcName"></param>
/// <returns></returns>
[DllImport("extism")]
unsafe internal static extern bool extism_plugin_function_exists(ExtismPlugin* plugin, string funcName);
/// <summary>
/// Call a function.
/// </summary>
/// <param name="plugin"></param>
/// <param name="funcName">The function to call.</param>
/// <param name="data">Input data.</param>
/// <param name="dataLen">The length of the `data` parameter.</param>
/// <returns></returns>
[DllImport("extism")]
unsafe internal static extern int extism_plugin_call(ExtismPlugin* plugin, string funcName, byte* data, int dataLen);
/// <summary>
/// Get the error associated with a Plugin
/// </summary>
/// <param name="plugin">A plugin pointer</param>
/// <returns></returns>
[DllImport("extism")]
unsafe internal static extern IntPtr extism_plugin_error(ExtismPlugin* plugin);
/// <summary>
/// Get the length of a plugin's output data.
/// </summary>
/// <param name="plugin"></param>
/// <returns></returns>
[DllImport("extism")]
unsafe internal static extern long extism_plugin_output_length(ExtismPlugin* plugin);
/// <summary>
/// Get the plugin's output data.
/// </summary>
/// <param name="plugin"></param>
/// <returns></returns>
[DllImport("extism")]
unsafe internal static extern IntPtr extism_plugin_output_data(ExtismPlugin* plugin);
/// <summary>
/// Set log file and level.
/// </summary>
/// <param name="filename"></param>
/// <param name="logLevel"></param>
/// <returns></returns>
[DllImport("extism")]
internal static extern bool extism_log_file(string filename, string logLevel);
/// <summary>
/// Get the Extism Plugin ID, a 16-bit UUID in host order
/// </summary>
/// <returns></returns>
// [DllImport("extism")]
// unsafe internal static extern IntPtr extism_plugin_id(ExtismPlugin* plugin);
/// <summary>
/// Extism Log Levels
/// </summary>
internal static class LogLevels
{
/// <summary>
/// Designates very serious errors.
/// </summary>
internal const string Error = "Error";
/// <summary>
/// Designates hazardous situations.
/// </summary>
internal const string Warn = "Warn";
/// <summary>
/// Designates useful information.
/// </summary>
internal const string Info = "Info";
/// <summary>
/// Designates lower priority information.
/// </summary>
internal const string Debug = "Debug";
/// <summary>
/// Designates very low priority, often extremely verbose, information.
/// </summary>
internal const string Trace = "Trace";
}
}

View File

@@ -1,32 +0,0 @@
namespace Extism.Sdk.Native;
/// <summary>
/// Extism Log Levels
/// </summary>
public enum LogLevel
{
/// <summary>
/// Designates very serious errors.
/// </summary>
Error,
/// <summary>
/// Designates hazardous situations.
/// </summary>
Warning,
/// <summary>
/// Designates useful information.
/// </summary>
Info,
/// <summary>
/// Designates lower priority information.
/// </summary>
Debug,
/// <summary>
/// Designates very low priority, often extremely verbose, information.
/// </summary>
Trace
}

View File

@@ -1,202 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace Extism.Sdk.Native;
/// <summary>
/// Represents a WASM Extism plugin.
/// </summary>
public unsafe class Plugin : IDisposable
{
private const int DisposedMarker = 1;
private readonly HostFunction[] _functions;
private int _disposed;
/// <summary>
/// Native pointer to the Extism Plugin.
/// </summary>
internal LibExtism.ExtismPlugin* NativeHandle { get; }
/// <summary>
/// Create a and load a plug-in
/// </summary>
/// <param name="wasm">A WASM module (wat or wasm) or a JSON encoded manifest.</param>
/// <param name="functions">List of host functions expected by the plugin.</param>
/// <param name="withWasi">Enable/Disable WASI.</param>
public Plugin(ReadOnlySpan<byte> wasm, HostFunction[] functions, bool withWasi) {
_functions = functions;
var functionHandles = functions.Select(f => f.NativeHandle).ToArray();
unsafe
{
fixed (byte* wasmPtr = wasm)
fixed (IntPtr* functionsPtr = functionHandles)
{
NativeHandle = LibExtism.extism_plugin_new(wasmPtr, wasm.Length, functionsPtr, functions.Length, withWasi, null);
if (NativeHandle == null)
{
throw new ExtismException("Unable to create plugin");
// TODO: handle error
// var s = Marshal.PtrToStringUTF8(result);
// LibExtism.extism_plugin_new_error_free(errmsg);
// throw new ExtismException(s);
}
}
}
}
/// <summary>
/// Update plugin config values, this will merge with the existing values.
/// </summary>
/// <param name="json">The configuration JSON encoded in UTF8.</param>
unsafe public bool SetConfig(ReadOnlySpan<byte> json)
{
CheckNotDisposed();
fixed (byte* jsonPtr = json)
{
return LibExtism.extism_plugin_config(NativeHandle, jsonPtr, json.Length);
}
}
/// <summary>
/// Checks if a specific function exists in the current plugin.
/// </summary>
unsafe public bool FunctionExists(string name)
{
CheckNotDisposed();
return LibExtism.extism_plugin_function_exists(NativeHandle, name);
}
/// <summary>
/// Calls a function in the current plugin and returns a status.
/// If the status represents an error, call <see cref="GetError"/> to get the error.
/// Othewise, call <see cref="OutputData"/> to get the function's output data.
/// </summary>
/// <param name="functionName">Name of the function in the plugin to invoke.</param>
/// <param name="data">A buffer to provide as input to the function.</param>
/// <returns>The exit code of the function.</returns>
/// <exception cref="ExtismException"></exception>
unsafe public ReadOnlySpan<byte> CallFunction(string functionName, ReadOnlySpan<byte> data)
{
CheckNotDisposed();
fixed (byte* dataPtr = data)
{
int response = LibExtism.extism_plugin_call(NativeHandle, functionName, dataPtr, data.Length);
if (response == 0)
{
return OutputData();
}
else
{
var errorMsg = GetError();
if (errorMsg != null)
{
throw new ExtismException(errorMsg);
}
else
{
throw new ExtismException("Call to Extism failed");
}
}
}
}
/// <summary>
/// Get the length of a plugin's output data.
/// </summary>
/// <returns></returns>
unsafe internal int OutputLength()
{
CheckNotDisposed();
return (int)LibExtism.extism_plugin_output_length(NativeHandle);
}
/// <summary>
/// Get the plugin's output data.
/// </summary>
internal ReadOnlySpan<byte> OutputData()
{
CheckNotDisposed();
var length = OutputLength();
unsafe
{
var ptr = LibExtism.extism_plugin_output_data(NativeHandle).ToPointer();
return new Span<byte>(ptr, length);
}
}
/// <summary>
/// Get the error associated with the current plugin.
/// </summary>
/// <returns></returns>
unsafe internal string? GetError()
{
CheckNotDisposed();
var result = LibExtism.extism_plugin_error(NativeHandle);
return Marshal.PtrToStringUTF8(result);
}
/// <summary>
/// Frees all resources held by this Plugin.
/// </summary>
public void Dispose()
{
if (Interlocked.Exchange(ref _disposed, DisposedMarker) == DisposedMarker)
{
// Already disposed.
return;
}
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Throw an appropriate exception if the plugin has been disposed.
/// </summary>
/// <exception cref="ObjectDisposedException"></exception>
protected void CheckNotDisposed()
{
Interlocked.MemoryBarrier();
if (_disposed == DisposedMarker)
{
ThrowDisposedException();
}
}
[DoesNotReturn]
private static void ThrowDisposedException()
{
throw new ObjectDisposedException(nameof(Plugin));
}
/// <summary>
/// Frees all resources held by this Plugin.
/// </summary>
unsafe protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free up any managed resources here
}
// Free up unmanaged resources
LibExtism.extism_plugin_free(NativeHandle);
}
/// <summary>
/// Destructs the current Plugin and frees all resources used by it.
/// </summary>
~Plugin()
{
Dispose(false);
}
}

View File

@@ -1,2 +0,0 @@
## Extism.Sdk
Extism SDK that allows hosting Extism plugins in .NET apps.

View File

@@ -1,58 +0,0 @@
using Extism.Sdk.Native;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using Xunit;
namespace Extism.Sdk.Tests;
public class BasicTests
{
[Fact]
public void CountHelloWorldVowels()
{
var binDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
var wasm = File.ReadAllBytes(Path.Combine(binDirectory, "code.wasm"));
using var plugin = new Plugin(wasm, Array.Empty<HostFunction>(), withWasi: true);
var response = plugin.CallFunction("count_vowels", Encoding.UTF8.GetBytes("Hello World"));
Assert.Equal("{\"count\": 3}", Encoding.UTF8.GetString(response));
}
[Fact]
public void CountVowelsHostFunctions()
{
var userData = Marshal.StringToHGlobalAnsi("Hello again!");
using var helloWorld = new HostFunction(
"hello_world",
"env",
new[] { ExtismValType.I64 },
new[] { ExtismValType.I64 },
userData,
HelloWorld);
var binDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
var wasm = File.ReadAllBytes(Path.Combine(binDirectory, "code-functions.wasm"));
using var plugin = new Plugin(wasm, new[] { helloWorld }, withWasi: true);
var response = plugin.CallFunction("count_vowels", Encoding.UTF8.GetBytes("Hello World"));
Assert.Equal("{\"count\": 3}", Encoding.UTF8.GetString(response));
void HelloWorld(CurrentPlugin plugin, Span<ExtismVal> inputs, Span<ExtismVal> outputs, nint data)
{
Console.WriteLine("Hello from .NET!");
var text = Marshal.PtrToStringAnsi(data);
Console.WriteLine(text);
var input = plugin.ReadString(new nint(inputs[0].v.i64));
Console.WriteLine($"Input: {input}");
var output = new string(input); // clone the string
outputs[0].v.i64 = plugin.WriteString(output);
}
}
}

View File

@@ -1,42 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\wasm\code.wasm" Link="code.wasm">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\..\..\wasm\code-functions.wasm" Link="code-functions.wasm">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Extism.Sdk\Extism.Sdk.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Extism.runtime.win-x64" Version="0.4.0" />
</ItemGroup>
</Project>

View File

@@ -1,116 +0,0 @@
; Configure which static analysis checks are enabled
[analysis.config.StaticAnalysisConfig]
; Check variable, class, struct, interface, union, and function names against t
; he Phobos style guide
style_check="enabled"
; Check for array literals that cause unnecessary allocation
enum_array_literal_check="enabled"
; Check for poor exception handling practices
exception_check="enabled"
; Check for use of the deprecated 'delete' keyword
delete_check="enabled"
; Check for use of the deprecated floating point operators
float_operator_check="enabled"
; Check number literals for readability
number_style_check="enabled"
; Checks that opEquals, opCmp, toHash, and toString are either const, immutable
; , or inout.
object_const_check="enabled"
; Checks for .. expressions where the left side is larger than the right.
backwards_range_check="enabled"
; Checks for if statements whose 'then' block is the same as the 'else' block
if_else_same_check="enabled"
; Checks for some problems with constructors
constructor_check="enabled"
; Checks for unused variables
unused_variable_check="enabled"
; Checks for unused labels
unused_label_check="enabled"
; Checks for unused function parameters
unused_parameter_check="enabled"
; Checks for duplicate attributes
duplicate_attribute="enabled"
; Checks that opEquals and toHash are both defined or neither are defined
opequals_tohash_check="enabled"
; Checks for subtraction from .length properties
length_subtraction_check="enabled"
; Checks for methods or properties whose names conflict with built-in propertie
; s
builtin_property_names_check="enabled"
; Checks for confusing code in inline asm statements
asm_style_check="enabled"
; Checks for confusing logical operator precedence
logical_precedence_check="enabled"
; Checks for undocumented public declarations
undocumented_declaration_check="enabled"
; Checks for poor placement of function attributes
function_attribute_check="enabled"
; Checks for use of the comma operator
comma_expression_check="enabled"
; Checks for local imports that are too broad. Only accurate when checking code
; used with D versions older than 2.071.0
local_import_check="disabled"
; Checks for variables that could be declared immutable
could_be_immutable_check="enabled"
; Checks for redundant expressions in if statements
redundant_if_check="enabled"
; Checks for redundant parenthesis
redundant_parens_check="enabled"
; Checks for mismatched argument and parameter names
mismatched_args_check="enabled"
; Checks for labels with the same name as variables
label_var_same_name_check="enabled"
; Checks for lines longer than `max_line_length` characters
long_line_check="enabled"
; The maximum line length used in `long_line_check`.
max_line_length="120"
; Checks for assignment to auto-ref function parameters
auto_ref_assignment_check="enabled"
; Checks for incorrect infinite range definitions
incorrect_infinite_range_check="enabled"
; Checks for asserts that are always true
useless_assert_check="enabled"
; Check for uses of the old-style alias syntax
alias_syntax_check="enabled"
; Checks for else if that should be else static if
static_if_else_check="enabled"
; Check for unclear lambda syntax
lambda_return_check="enabled"
; Check for auto function without return statement
auto_function_check="enabled"
; Check for sortedness of imports
imports_sortedness="disabled"
; Check for explicitly annotated unittests
explicitly_annotated_unittests="disabled"
; Check for properly documented public functions (Returns, Params)
properly_documented_public_functions="disabled"
; Check for useless usage of the final attribute
final_attribute_check="enabled"
; Check for virtual calls in the class constructors
vcall_in_ctor="enabled"
; Check for useless user defined initializers
useless_initializer="disabled"
; Check allman brace style
allman_braces_check="disabled"
; Check for redundant attributes
redundant_attributes_check="enabled"
; Check public declarations without a documented unittest
has_public_example="disabled"
; Check for asserts without an explanatory message
assert_without_msg="disabled"
; Check indent of if constraints
if_constraints_indent="disabled"
; Check for @trusted applied to a bigger scope than a single function
trust_too_much="enabled"
; Check for redundant storage classes on variable declarations
redundant_storage_classes="enabled"
; Check for unused function return values
unused_result="enabled"
; Enable cyclomatic complexity check
cyclomatic_complexity="disabled"
; Maximum cyclomatic complexity after which to issue warnings
max_cyclomatic_complexity="50"
; Check for function bodies on disabled functions
body_on_disabled_func_check="enabled"
; ModuleFilters for selectively enabling (+std) and disabling (-std.internal) individual checks
[analysis.config.ModuleFilters]

View File

@@ -1,23 +0,0 @@
{
"name": "extism",
"description": "The Universal Plug-in System. Extend anything with WebAssembly (wasm).",
"license": "BSD-3-Clause",
"authors": [
"Chance Snow <git@chancesnow.me>",
"Extism contributors"
],
"copyright": "Copyright © 2023, Extism contributors",
"toolchainRequirements": {
"frontend": ">=2.102"
},
"targetPath": "target",
"sourceFiles": ["d/extism.d"],
"importPaths": ["d"],
"systemDependencies": "extism >= 0.4.0",
"targetType": "sourceLibrary",
"subPackages": [
"d/examples/hello"
],
"dflags": ["-P-I$EXTISM_PACKAGE_DIR"],
"libs": ["extism"]
}

Some files were not shown because too many files have changed in this diff Show More