Skip to content

Commit

Permalink
feat: seperate pointer from handle (#18)
Browse files Browse the repository at this point in the history
* feat: split ExtismPointer with ExtismHandle

* use generic load functions instead of input imports

* chore: add input_length import back, as long as it exists, no point in not using it

* docs: update to new api

* chore: add length_unsafe, switch handle api to use it, add extism_length_safe to low level api
  • Loading branch information
G4Vi authored Jan 4, 2024
1 parent 01064c0 commit 6e3323b
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 179 deletions.
84 changes: 43 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ int32_t EXTISM_EXPORTED_FUNCTION(greet) {

// Load input
static uint8_t inputData[Greet_Max_Input];
extism_load_input(inputData, inputLen);
extism_load_input(0, inputData, inputLen);

// Allocate a new offset used to store greeting and name
// Allocate memory to store greeting and name
const uint64_t greetingLen = sizeof(Greeting) - 1;
const uint64_t outputLen = greetingLen + inputLen;
ExtismPointer offs = extism_alloc(outputLen);
extism_store(offs, (const uint8_t *)Greeting, greetingLen);
extism_store(offs + greetingLen, inputData, inputLen);
ExtismHandle handle = extism_alloc(outputLen);
extism_store_to_handle(handle, 0, Greeting, greetingLen);
extism_store_to_handle(handle, greetingLen, inputData, inputLen);

// Set output
extism_output_set(offs, outputLen);
extism_output_set_from_handle(handle, 0, outputLen);
return 0;
}
```
Expand All @@ -71,7 +71,7 @@ command:

```bash
extism call plugin.wasm greet --input="Benjamin"
# => Hello, Benjamin!
# => Hello, Benjamin
```

### More Exports: Error Handling
Expand Down Expand Up @@ -101,26 +101,26 @@ int32_t EXTISM_EXPORTED_FUNCTION(greet) {

// Load input
static uint8_t inputData[Greet_Max_Input];
extism_load_input(inputData, inputLen);
extism_load_input(0, inputData, inputLen);
inputData[inputLen] = '\0';

// Check if the input matches "benjamin", if it does
// return an error
if (is_benjamin((const char *)inputData)) {
ExtismPointer err = extism_alloc_string("ERROR", 5);
ExtismHandle err = extism_alloc_buf_from_sz("ERROR");
extism_error_set(err);
return -1;
}

// Allocate a new offset used to store greeting and name
// Allocate memory to store greeting and name
const uint64_t greetingLen = sizeof(Greeting) - 1;
const uint64_t outputLen = greetingLen + inputLen;
ExtismPointer offs = extism_alloc(outputLen);
extism_store(offs, (const uint8_t *)Greeting, greetingLen);
extism_store(offs + greetingLen, inputData, inputLen);
ExtismHandle handle = extism_alloc(outputLen);
extism_store_to_handle(handle, 0, Greeting, greetingLen);
extism_store_to_handle(handle, greetingLen, inputData, inputLen);

// Set output
extism_output_set(offs, outputLen);
extism_output_set_from_handle(handle, 0, outputLen);
return 0;
}
```
Expand All @@ -135,7 +135,7 @@ extism call plugin.wasm greet --input="Benjamin" --wasi
echo $? # print last status code
# => 1
extism call plugin.wasm greet --input="Zach" --wasi
# => Hello, Zach!
# => Hello, Zach
echo $?
# => 0
```
Expand All @@ -155,12 +155,12 @@ plug-in. These can be useful to statically configure the plug-in with some data
static const char Greeting[] = "Hello, ";

int32_t EXTISM_EXPORTED_FUNCTION(greet) {
ExtismPointer key = extism_alloc_string("user", 4);
ExtismPointer value = extism_config_get(key);
ExtismHandle key = extism_alloc_buf_from_sz("user");
ExtismHandle value = extism_config_get(key);
extism_free(key);

if (value == 0) {
ExtismPointer err = extism_alloc_string("Invalid key", 11);
ExtismHandle err = extism_alloc_buf_from_sz("Invalid key");
extism_error_set(err);
return -1;
}
Expand All @@ -170,22 +170,22 @@ int32_t EXTISM_EXPORTED_FUNCTION(greet) {
// Load config value
uint8_t *valueData = malloc(valueLen);
if (valueData == NULL) {
ExtismPointer err = extism_alloc_string("OOM", 11);
ExtismHandle err = extism_alloc_buf_from_sz("OOM");
extism_error_set(err);
return -1;
}
extism_load(value, valueData, valueLen);
extism_load_from_handle(value, 0, valueData, valueLen);

// Allocate a new offset used to store greeting and name
// Allocate memory to store greeting and name
const uint64_t greetingLen = sizeof(Greeting) - 1;
const uint64_t outputLen = greetingLen + valueLen;
ExtismPointer offs = extism_alloc(outputLen);
extism_store(offs, (const uint8_t *)Greeting, greetingLen);
extism_store(offs + greetingLen, valueData, valueLen);
ExtismHandle handle = extism_alloc(outputLen);
extism_store_to_handle(handle, 0, Greeting, greetingLen);
extism_store_to_handle(handle, greetingLen, valueData, valueLen);
free(valueData);

// Set output
extism_output_set(offs, outputLen);
extism_output_set_from_handle(handle, 0, outputLen);
return 0;
}
```
Expand All @@ -195,7 +195,7 @@ To test it, the [Extism CLI](https://github.com/extism/cli) has a `--config` opt
```bash
extism call plugin.wasm greet --config user=Benjamin
# => Hello, Benjamin!
# => Hello, Benjamin
```

### Variables
Expand All @@ -211,12 +211,12 @@ You can use `extism_var_get`, and `extism_var_set` to manipulate vars:
#include <stdint.h>

int32_t EXTISM_EXPORTED_FUNCTION(count) {
ExtismPointer key = extism_alloc_string("count", 5);
ExtismPointer value = extism_var_get(key);
ExtismHandle key = extism_alloc_buf_from_sz("count");
ExtismHandle value = extism_var_get(key);

uint64_t count = 0;
if (value != 0) {
extism_load(value, (uint8_t *)&count, sizeof(uint64_t));
extism_load_from_handle(value, 0, &count, sizeof(uint64_t));
}
count += 1;

Expand All @@ -226,7 +226,7 @@ int32_t EXTISM_EXPORTED_FUNCTION(count) {
}

// Update the memory block
extism_store(value, (uint8_t *)&count, sizeof(uint64_t));
extism_store_to_handle(value, 0, &count, sizeof(uint64_t));

// Set the variable
extism_var_set(key, value);
Expand All @@ -250,12 +250,12 @@ The `extism_log*` functions can be used to emit logs:
#include <stdint.h>
int32_t EXTISM_EXPORTED_FUNCTION(log_stuff) {
ExtismPointer msg = extism_alloc_string("Hello!", 6);
ExtismHandle msg = extism_alloc_buf_from_sz("Hello!");
extism_log_info(msg);
extism_log_debug(msg);
extism_log_warn(msg);
extism_log_error(msg);
extism_log("Hello!", 6, ExtismLogInfo);
extism_log_sz("Hello!", ExtismLogInfo);
return 0;
}
```
Expand Down Expand Up @@ -288,14 +288,14 @@ int32_t EXTISM_EXPORTED_FUNCTION(call_http) {
\"url\": \"https://jsonplaceholder.typicode.com/todos/1\"\
}";

ExtismPointer req = extism_alloc_string(reqStr, strlen(reqStr));
ExtismPointer res = extism_http_request(req, 0);
ExtismHandle req = extism_alloc_buf_from_sz(reqStr);
ExtismHandle res = extism_http_request(req, 0);

if (extism_http_status_code() != 200) {
return -1;
}

extism_output_set(res, extism_length(res));
extism_output_set_from_handle(res, 0, extism_length(res));
return 0;
}
```
Expand All @@ -318,29 +318,29 @@ to do this correctly. So we recommend reading out [concept doc on Host Functions
Host functions have a similar interface as exports. You just need to declare them as `extern` on the top of your header file. You only declare the interface as it is the host's responsibility to provide the implementation:
```c
extern ExtismPointer a_python_func(ExtismPointer);
extern ExtismHandle a_python_func(ExtismHandle);
```

A namespace may be set for an import using the `IMPORT` macro in `extism-pdk.h`:

```c
IMPORT("my_module", "a_python_func") extern ExtismPointer a_python_func(ExtismPointer);
IMPORT("my_module", "a_python_func") extern ExtismHandle a_python_func(ExtismHandle);
```
> **Note**: The types we accept here are the same as the exports as the interface also uses the [convert crate](https://docs.rs/extism-convert/latest/extism_convert/).
To call this function, we pass an Extism pointer and receive one back:
To call this function, we pass an Extism handle and receive one back:
```c
#define EXTISM_IMPLEMENTATION
#include "extism-pdk.h"
#include <stdint.h>
int32_t EXTISM_EXPORTED_FUNCTION(hello_from_python) {
ExtismPointer arg = extism_alloc_string("Hello!", 6);
ExtismPointer res = a_python_func(arg);
ExtismHandle arg = extism_alloc_buf_from_sz("Hello!");
ExtismHandle res = a_python_func(arg);
extism_free(arg);
extism_output_set(res, extism_length(res));
extism_output_set_from_handle(res, 0, extism_length(res));
return 0;
}
```
Expand Down Expand Up @@ -407,6 +407,8 @@ All other source files using the pdk must include the header without `#define EX

The C PDK does not require building with `libc`, but additional functions can be enabled when `libc` is available. `#define EXTISM_USE_LIBC` in each file before including the pdk (everywhere it is included) or, when compiling, pass it as a flag to clang: `-D EXTISM_USE_LIBC`

The low-level API that operates on `ExtismPointer` is no longer included by default, `#define EXTISM_ENABLE_LOW_LEVEL_API` in each file before including the pdk (everywhere it is included) or, when compiling, pass it as a flag to clang: `-D EXTISM_ENABLE_LOW_LEVEL_API` . Updating to use the `ExtismHandle`-based API is highly recommended.

The C PDK may be used from C++, however, the implementation must be built with a C compiler. See `cplusplus` in `tests/Makefile` for an example.

## Exports (details)
Expand Down
7 changes: 4 additions & 3 deletions examples/count-vowels/count-vowels.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#define EXTISM_ENABLE_LOW_LEVEL_API
#define EXTISM_IMPLEMENTATION
#include "../../extism-pdk.h"

Expand All @@ -19,9 +20,9 @@ int32_t EXTISM_EXPORTED_FUNCTION(count_vowels) {
char out[128];
int n = snprintf(out, 128, "{\"count\": %llu}", count);

uint64_t offs_ = extism_alloc(n);
extism_store(offs_, (const uint8_t *)out, n);
extism_output_set(offs_, n);
ExtismHandle buf = extism_alloc(n);
extism_store(buf, out, n);
extism_output_set(buf, n);

return 0;
}
6 changes: 3 additions & 3 deletions examples/globals/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ int32_t EXTISM_EXPORTED_FUNCTION(globals) {
char out[128];
int n = snprintf(out, 128, "{\"count\": %llu}", count);

uint64_t offs_ = extism_alloc(n);
extism_store(offs_, (const uint8_t *)out, n);
extism_output_set(offs_, n);
ExtismHandle buf = extism_alloc(n);
extism_store_to_handle(buf, 0, out, n);
extism_output_set_from_handle(buf, 0, n);

count += 1;

Expand Down
11 changes: 6 additions & 5 deletions examples/host-functions/host-functions.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#define EXTISM_ENABLE_LOW_LEVEL_API
#define EXTISM_IMPLEMENTATION
#include "../../extism-pdk.h"

#include <stdio.h>

EXTISM_IMPORT("extism:host/user", "hello_world")
extern uint64_t hello_world(uint64_t);
extern ExtismHandle hello_world(ExtismHandle);

int32_t EXTISM_EXPORTED_FUNCTION(count_vowels) {
uint64_t length = extism_input_length();
Expand All @@ -25,9 +26,9 @@ int32_t EXTISM_EXPORTED_FUNCTION(count_vowels) {

char out[128];
int n = snprintf(out, 128, "{\"count\": %lld}", count);
uint64_t offs_ = extism_alloc(n);
extism_store(offs_, (const uint8_t *)out, n);
offs_ = hello_world(offs_);
extism_output_set(offs_, extism_length(offs_));
ExtismHandle buf = extism_alloc(n);
extism_store_to_handle(buf, 0, out, n);
buf = hello_world(buf);
extism_output_set(buf, extism_length(buf));
return 0;
}
Loading

0 comments on commit 6e3323b

Please sign in to comment.