diff --git a/CMakeLists.txt b/CMakeLists.txt index 52606eb..f4eedf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.18) include_guard(GLOBAL) -set (CMAKE_CXX_STANDARD 14) +set (CMAKE_CXX_STANDARD 17) # extism-cpp library project(extism-cpp VERSION 1.0.0 DESCRIPTION "C++ bindings for libextism") @@ -51,7 +51,8 @@ set_target_properties(extism-cpp PROPERTIES PUBLIC_HEADER src/extism.hpp) target_include_directories(extism-cpp PUBLIC $ ) -target_link_libraries(extism-cpp PUBLIC extism-shared jsoncpp_lib) +target_link_libraries(extism-cpp PUBLIC extism-shared) +target_link_libraries(extism-cpp PRIVATE jsoncpp_lib) set_target_properties(extism-cpp PROPERTIES NO_SONAME 1 ) @@ -68,10 +69,10 @@ target_include_directories(extism-cpp-static PUBLIC ) target_link_libraries(extism-cpp-static PUBLIC extism-static) if(TARGET jsoncpp_static) - target_link_libraries(extism-cpp-static PUBLIC jsoncpp_static) + target_link_libraries(extism-cpp-static PRIVATE jsoncpp_static) else() message(WARNING "jsoncpp_static not found, linking jsoncpp_lib instead") - target_link_libraries(extism-cpp-static PUBLIC jsoncpp_lib) + target_link_libraries(extism-cpp-static PRIVATE jsoncpp_lib) endif() configure_file(extism-cpp-static.pc.in extism-cpp-static.pc @ONLY) list(APPEND CMAKE_TARGETS extism-cpp-static) diff --git a/example.cpp b/example.cpp index 1d8f1a5..9e7b05a 100644 --- a/example.cpp +++ b/example.cpp @@ -39,7 +39,7 @@ int main(int argc, char *argv[]) { Plugin plugin(wasm, true, functions); const char *input = argc > 1 ? argv[1] : "this is a test"; - ExtismSize length = strlen(input); + size_t length = strlen(input); extism::Buffer output = plugin.call("count_vowels", (uint8_t *)input, length); std::cout << (char *)output.data << std::endl; diff --git a/src/current_plugin.cpp b/src/current_plugin.cpp index 8bf9ec3..ceb06e1 100644 --- a/src/current_plugin.cpp +++ b/src/current_plugin.cpp @@ -1,46 +1,46 @@ #include "extism.hpp" +#include +#include namespace extism { -uint8_t *CurrentPlugin::memory() { +uint8_t *CurrentPlugin::memory() const { return extism_current_plugin_memory(this->pointer); } -uint8_t *CurrentPlugin::memory(MemoryHandle offs) { +uint8_t *CurrentPlugin::memory(MemoryHandle offs) const { return this->memory() + offs; } -ExtismSize CurrentPlugin::memoryLength(MemoryHandle offs) { +ExtismSize CurrentPlugin::memoryLength(MemoryHandle offs) const { return extism_current_plugin_memory_length(this->pointer, offs); } -MemoryHandle CurrentPlugin::memoryAlloc(ExtismSize size) { +MemoryHandle CurrentPlugin::memoryAlloc(ExtismSize size) const { return extism_current_plugin_memory_alloc(this->pointer, size); } -void CurrentPlugin::memoryFree(MemoryHandle handle) { +void CurrentPlugin::memoryFree(MemoryHandle handle) const { extism_current_plugin_memory_free(this->pointer, handle); } -void CurrentPlugin::output(const std::string &s, size_t index) { - this->output((const uint8_t *)s.c_str(), s.size(), index); +bool CurrentPlugin::output(std::string_view s, size_t index) const { + return this->output(reinterpret_cast(s.data()), s.size(), + index); } -void CurrentPlugin::output(const uint8_t *bytes, size_t len, size_t index) { - if (index < this->nInputs) { +bool CurrentPlugin::output(const uint8_t *bytes, size_t len, + size_t index) const { + if (index < this->nOutputs) { auto offs = this->memoryAlloc(len); memcpy(this->memory() + offs, bytes, len); this->outputs[index].v.i64 = offs; + return true; } + return false; } -void CurrentPlugin::output(const Json::Value &&v, size_t index) { - Json::FastWriter writer; - const std::string s = writer.write(v); - this->output(s, index); -} - -uint8_t *CurrentPlugin::inputBytes(size_t *length, size_t index) { +uint8_t *CurrentPlugin::inputBytes(size_t *length, size_t index) const { if (index >= this->nInputs) { return nullptr; } @@ -54,19 +54,19 @@ uint8_t *CurrentPlugin::inputBytes(size_t *length, size_t index) { return this->memory() + inp.v.i64; } -Buffer CurrentPlugin::inputBuffer(size_t index) { +Buffer CurrentPlugin::inputBuffer(size_t index) const { size_t length = 0; auto ptr = inputBytes(&length, index); return Buffer(ptr, length); } -std::string CurrentPlugin::inputString(size_t index) { +std::string_view CurrentPlugin::inputStringView(size_t index) const { size_t length = 0; - char *buf = (char *)this->inputBytes(&length, index); - return std::string(buf, length); + auto buf = reinterpret_cast(this->inputBytes(&length, index)); + return std::string_view(buf, length); } -const Val &CurrentPlugin::inputVal(size_t index) { +const Val &CurrentPlugin::inputVal(size_t index) const { if (index >= nInputs) { throw Error("Input out of bounds"); } @@ -74,7 +74,7 @@ const Val &CurrentPlugin::inputVal(size_t index) { return this->inputs[index]; } -Val &CurrentPlugin::outputVal(size_t index) { +Val &CurrentPlugin::outputVal(size_t index) const { if (index >= nOutputs) { throw Error("Output out of bounds"); } diff --git a/src/extism.cpp b/src/extism.cpp index 0fc14d3..6ce45cf 100644 --- a/src/extism.cpp +++ b/src/extism.cpp @@ -8,5 +8,5 @@ inline bool setLogFile(const char *filename, const char *level) { } // Get libextism version -inline std::string version() { return std::string(extism_version()); } +inline std::string_view version() { return extism_version(); } }; // namespace extism \ No newline at end of file diff --git a/src/extism.hpp b/src/extism.hpp index dc6f1aa..d86d095 100644 --- a/src/extism.hpp +++ b/src/extism.hpp @@ -1,43 +1,26 @@ #pragma once -#include +#include +#include #include #include #include +#include #include #include +#include #include -#include - -extern "C" { -#include -} - namespace extism { class Error : public std::runtime_error { public: - Error(std::string msg) : std::runtime_error(msg) {} + Error(const std::string &msg) : std::runtime_error(msg) {} + Error(const char *msg) : std::runtime_error(msg) {} }; typedef std::map Config; -template 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; } -}; - enum WasmSource { WasmSourcePath, WasmSourceURL, WasmSourceBytes }; class Wasm { @@ -47,44 +30,40 @@ class Wasm { std::map httpHeaders; // TODO: add base64 encoded raw data - ManifestKey _hash = - ManifestKey(std::string(), false); + std::string _hash; public: Wasm(WasmSource source, std::string ref, std::string hash = std::string()) - : source(source), ref(ref), _hash(hash) {} + : source(source), ref(std::move(ref)), _hash(std::move(hash)) {} // Create Wasm pointing to a path - static Wasm path(std::string s, std::string hash = std::string()) { - return Wasm(WasmSourcePath, s, hash); - } + static Wasm path(std::string s, std::string hash = std::string()); // Create Wasm pointing to a URL static Wasm url(std::string s, std::string hash = std::string(), std::string method = "GET", - std::map headers = - std::map()) { - auto wasm = Wasm(WasmSourceURL, s, hash); - wasm.httpMethod = method; - wasm.httpHeaders = headers; - return wasm; - } + std::map headers = {}); + + // Create Wasm from bytes of a module + static Wasm bytes(const uint8_t *data, const size_t len, + std::string hash = std::string()); - Json::Value json(); + // Create Wasm from bytes of a module + static Wasm bytes(const std::vector &data, + std::string hash = std::string()); + + friend class Serializer; }; class Manifest { public: Config config; std::vector wasm; - ManifestKey> allowedHosts; - ManifestKey> allowedPaths; - ManifestKey timeout; + std::vector allowedHosts; + std::map allowedPaths; + std::optional timeout; - // Empty manifest - Manifest() - : timeout(0, false), allowedHosts(std::vector(), false), - allowedPaths(std::map(), false) {} + Manifest() {} // Create manifest with a single Wasm from a path static Manifest wasmPath(std::string s, std::string hash = std::string()); @@ -92,6 +71,11 @@ class Manifest { // Create manifest with a single Wasm from a URL static Manifest wasmURL(std::string s, std::string hash = std::string()); + // Create manifest from Wasm data + static Manifest wasmBytes(const uint8_t *data, const size_t len, + std::string hash = std::string()); + static Manifest wasmBytes(const std::vector &data, std::string hash); + std::string json() const; // Add Wasm from path @@ -100,6 +84,11 @@ class Manifest { // Add Wasm from URL void addWasmURL(std::string u, std::string hash = std::string()); + // add Wasm from bytes + void addWasmBytes(const uint8_t *data, const size_t len, + std::string hash = std::string()); + void addWasmBytes(const std::vector &data, std::string hash); + // Add host to allowed hosts void allowHost(std::string host); @@ -115,16 +104,22 @@ class Manifest { class Buffer { public: - Buffer(const uint8_t *ptr, ExtismSize len) : data(ptr), length(len) {} - const uint8_t *data; - ExtismSize length; + Buffer(const uint8_t *ptr, size_t len) : data(ptr), length(len) {} + const uint8_t *const data; + const size_t length; - std::string string() { return (std::string)(*this); } + std::string_view string() const { + return static_cast(*this); + } - std::vector vector() { return (std::vector)(*this); } + std::vector vector() const { + return static_cast>(*this); + } - operator std::string() { return std::string((const char *)data, length); } - operator std::vector() { + operator std::string_view() const { + return std::string_view(reinterpret_cast(data), length); + } + operator std::vector() const { return std::vector(data, data + length); } }; @@ -135,11 +130,11 @@ typedef ExtismVal Val; typedef uint64_t MemoryHandle; class CurrentPlugin { - ExtismCurrentPlugin *pointer; - const ExtismVal *inputs; - size_t nInputs; - ExtismVal *outputs; - size_t nOutputs; + ExtismCurrentPlugin *const pointer; + const ExtismVal *const inputs; + const size_t nInputs; + ExtismVal *const outputs; + const size_t nOutputs; public: CurrentPlugin(ExtismCurrentPlugin *p, const ExtismVal *inputs, size_t nInputs, @@ -147,19 +142,18 @@ class CurrentPlugin { : pointer(p), inputs(inputs), nInputs(nInputs), outputs(outputs), nOutputs(nOutputs) {} - uint8_t *memory(); - uint8_t *memory(MemoryHandle offs); - ExtismSize memoryLength(MemoryHandle offs); - MemoryHandle memoryAlloc(ExtismSize size); - void memoryFree(MemoryHandle handle); - void output(const std::string &s, size_t index = 0); - void output(const uint8_t *bytes, size_t len, size_t index = 0); - void output(const Json::Value &&v, size_t index = 0); - uint8_t *inputBytes(size_t *length = nullptr, size_t index = 0); - Buffer inputBuffer(size_t index = 0); - std::string inputString(size_t index = 0); - const Val &inputVal(size_t index); - Val &outputVal(size_t index); + uint8_t *memory() const; + uint8_t *memory(MemoryHandle offs) const; + ExtismSize memoryLength(MemoryHandle offs) const; + MemoryHandle memoryAlloc(ExtismSize size) const; + void memoryFree(MemoryHandle handle) const; + bool output(std::string_view s, size_t index = 0) const; + bool output(const uint8_t *bytes, size_t len, size_t index = 0) const; + uint8_t *inputBytes(size_t *length = nullptr, size_t index = 0) const; + Buffer inputBuffer(size_t index = 0) const; + std::string_view inputStringView(size_t index = 0) const; + const Val &inputVal(size_t index) const; + Val &outputVal(size_t index) const; }; typedef std::function FunctionType; @@ -178,41 +172,45 @@ class Function { UserData userData; public: - Function(std::string name, const std::vector inputs, - const std::vector outputs, FunctionType f, + Function(std::string name, const std::vector &inputs, + const std::vector &outputs, FunctionType f, void *userData = NULL, std::function free = nullptr); - Function(std::string ns, std::string name, const std::vector inputs, - const std::vector outputs, FunctionType f, - void *userData = NULL, std::function free = nullptr) { - this->setNamespace(ns); - } + Function(const std::string &ns, std::string name, + const std::vector &inputs, + const std::vector &outputs, FunctionType f, + void *userData = NULL, std::function free = nullptr); - void setNamespace(std::string s); + void setNamespace(const std::string &s) const; Function(const Function &f); - ExtismFunction *get(); + ExtismFunction *get() const; }; class Plugin { std::vector functions; + struct PluginDeleter { + void operator()(ExtismPlugin *) const; + }; + using unique_plugin = std::unique_ptr; + unique_plugin plugin; + public: class CancelHandle { const ExtismCancelHandle *handle; public: CancelHandle(const ExtismCancelHandle *x) : handle(x){}; - bool cancel() { return extism_plugin_cancel(this->handle); } + bool cancel(); }; - ExtismPlugin *plugin; // Create a new plugin - Plugin(const uint8_t *wasm, ExtismSize length, bool withWasi = false, + Plugin(const uint8_t *wasm, size_t length, bool withWasi = false, std::vector functions = std::vector()); - Plugin(const std::string &str, bool withWasi = false, + Plugin(std::string_view str, bool withWasi = false, std::vector functions = {}); Plugin(const std::vector &data, bool withWasi = false, @@ -224,32 +222,48 @@ class Plugin { Plugin(const Manifest &manifest, bool withWasi = false, std::vector functions = {}); - ~Plugin(); - void config(const Config &data); void config(const char *json, size_t length); - void config(const std::string &json); + void config(std::string_view json); + + // Call a plugin + Buffer call(const char *func, const uint8_t *input, size_t inputLength) const; + + // Call a plugin function with std::vector input + Buffer call(const char *func, const std::vector &input) const; + + // Call a plugin function with string input + Buffer call(const char *func, std::string_view input = "") const; // Call a plugin Buffer call(const std::string &func, const uint8_t *input, - ExtismSize inputLength) const; + size_t inputLength) const; // Call a plugin function with std::vector input Buffer call(const std::string &func, const std::vector &input) const; // Call a plugin function with string input - Buffer call(const std::string &func, - const std::string &input = std::string()) const; + Buffer call(const std::string &func, std::string_view input = "") const; + + // Returns true if the specified function exists + bool functionExists(const char *func) const; // Returns true if the specified function exists bool functionExists(const std::string &func) const; + + // Reset the Extism runtime, this will invalidate all allocated memory + // returns true if it succeeded + bool reset() const; + + // Get a ptr to the plugin that can be passed to the c api + ExtismPlugin *get() const { return plugin.get(); } }; // Set global log file for plugins inline bool setLogFile(const char *filename, const char *level); // Get libextism version -inline std::string version(); +inline std::string_view version(); } // namespace extism diff --git a/src/function.cpp b/src/function.cpp index a9c4848..92a2d4f 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -5,22 +5,22 @@ static void functionCallback(ExtismCurrentPlugin *plugin, const ExtismVal *inputs, ExtismSize n_inputs, ExtismVal *outputs, ExtismSize n_outputs, void *user_data) { - Function::UserData *data = (Function::UserData *)user_data; + Function::UserData *data = static_cast(user_data); data->func(CurrentPlugin(plugin, inputs, n_inputs, outputs, n_outputs), data->userData); } static void freeUserData(void *user_data) { - Function::UserData *data = (Function::UserData *)user_data; + Function::UserData *data = static_cast(user_data); if (data->userData != nullptr && data->freeUserData != nullptr) { data->freeUserData(data->userData); } } -Function::Function(std::string name, const std::vector inputs, - const std::vector outputs, FunctionType f, +Function::Function(std::string name, const std::vector &inputs, + const std::vector &outputs, FunctionType f, void *userData, std::function free) - : name(name) { + : name(std::move(name)) { this->userData.func = f; this->userData.userData = userData; this->userData.freeUserData = free; @@ -30,12 +30,20 @@ Function::Function(std::string name, const std::vector inputs, this->func = std::shared_ptr(ptr, extism_function_free); } -void Function::setNamespace(std::string s) { +Function::Function(const std::string &ns, std::string name, + const std::vector &inputs, + const std::vector &outputs, FunctionType f, + void *userData, std::function free) + : Function(std::move(name), inputs, outputs, f, userData, free) { + this->setNamespace(ns); +} + +void Function::setNamespace(const std::string &s) const { extism_function_set_namespace(this->func.get(), s.c_str()); } Function::Function(const Function &f) { this->func = f.func; } -ExtismFunction *Function::get() { return this->func.get(); } +ExtismFunction *Function::get() const { return this->func.get(); } }; // namespace extism diff --git a/src/manifest.cpp b/src/manifest.cpp index 7934393..e690b18 100644 --- a/src/manifest.cpp +++ b/src/manifest.cpp @@ -1,12 +1,92 @@ #include "extism.hpp" +#include +#include namespace extism { +static std::string base64_encode(const uint8_t *data, size_t len) { + const size_t out_len = ((len + 3 - 1) / 3) * 4; + std::string out(out_len, '\0'); + static const char alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + char *out_cursor = out.data(); + while (len > 0) { + const size_t to_encode = std::min(3, len); + len -= to_encode; + uint8_t c[4]; + c[1] = c[2] = 0; + memcpy(c, data, to_encode); + data += to_encode; + const uint32_t u = + (uint32_t)c[0] << 16 | (uint32_t)c[1] << 8 | (uint32_t)c[2]; + *out_cursor++ = alpha[u >> 18]; + *out_cursor++ = alpha[u >> 12 & 63]; + *out_cursor++ = to_encode < 2 ? '=' : alpha[u >> 6 & 63]; + *out_cursor++ = to_encode < 3 ? '=' : alpha[u & 63]; + } + return out; +} + +// Create Wasm pointing to a path +Wasm Wasm::path(std::string s, std::string hash) { + return Wasm(WasmSourcePath, std::move(s), std::move(hash)); +} + +// Create Wasm pointing to a URL +Wasm Wasm::url(std::string s, std::string hash, std::string method, + std::map headers) { + auto wasm = Wasm(WasmSourceURL, std::move(s), std::move(hash)); + wasm.httpMethod = std::move(method); + wasm.httpHeaders = std::move(headers); + return wasm; +} + +// Create Wasm from bytes of a module +Wasm Wasm::bytes(const uint8_t *data, const size_t len, std::string hash) { + std::string s = base64_encode(data, len); + return Wasm(WasmSourceBytes, std::move(s), std::move(hash)); +} + +Wasm Wasm::bytes(const std::vector &data, std::string hash) { + return Wasm::bytes(data.data(), data.size(), hash); +} + +class Serializer { +public: + static Json::Value json(const Wasm &wasm) { + Json::Value doc; + + if (wasm.source == WasmSourcePath) { + doc["path"] = wasm.ref; + } else if (wasm.source == WasmSourceURL) { + doc["url"] = wasm.ref; + doc["method"] = wasm.httpMethod; + if (!wasm.httpHeaders.empty()) { + Json::Value h; + for (auto k : wasm.httpHeaders) { + h[k.first] = k.second; + } + doc["headers"] = h; + } + } else if (wasm.source == WasmSourceBytes) { + doc["data"] = wasm.ref; + } + + if (!wasm._hash.empty()) { + doc["hash"] = wasm._hash; + } + + return doc; + } +}; + std::string Manifest::json() const { Json::Value doc; Json::Value wasm; for (auto w : this->wasm) { - wasm.append(w.json()); + wasm.append(Serializer::json(w)); } doc["wasm"] = wasm; @@ -23,7 +103,7 @@ std::string Manifest::json() const { if (!this->allowedHosts.empty()) { Json::Value h; - for (auto s : this->allowedHosts.value) { + for (auto s : this->allowedHosts) { h.append(s); } doc["allowed_hosts"] = h; @@ -31,96 +111,92 @@ std::string Manifest::json() const { if (!this->allowedPaths.empty()) { Json::Value h; - for (auto k : this->allowedPaths.value) { + for (auto k : this->allowedPaths) { h[k.first] = k.second; } doc["allowed_paths"] = h; } - if (!this->timeout.empty()) { - doc["timeout_ms"] = Json::Value(this->timeout.value); + if (this->timeout.has_value()) { + doc["timeout_ms"] = Json::Value(*this->timeout); } Json::FastWriter writer; return writer.write(doc); } -Json::Value Wasm::json() { - - Json::Value doc; - - if (this->source == WasmSourcePath) { - doc["path"] = this->ref; - } else if (this->source == WasmSourceURL) { - doc["url"] = this->ref; - doc["method"] = this->httpMethod; - if (!this->httpHeaders.empty()) { - Json::Value h; - for (auto k : this->httpHeaders) { - h[k.first] = this->httpHeaders[k.second]; - } - doc["headers"] = h; - } - } else if (this->source == WasmSourceBytes) { - throw Error("TODO: WasmSourceBytes"); - } - - if (!this->_hash.empty()) { - doc["hash"] = this->_hash.value; - } - - return doc; -} - Manifest Manifest::wasmPath(std::string s, std::string hash) { Manifest m; - m.addWasmPath(s, hash); + m.addWasmPath(std::move(s), std::move(hash)); return m; } // Create manifest with a single Wasm from a URL Manifest Manifest::wasmURL(std::string s, std::string hash) { Manifest m; - m.addWasmURL(s, hash); + m.addWasmURL(std::move(s), std::move(hash)); + return m; +} + +// Create manifest from Wasm data +Manifest Manifest::wasmBytes(const uint8_t *data, const size_t len, + std::string hash) { + Manifest m; + m.addWasmBytes(data, len, std::move(hash)); + return m; +} + +Manifest Manifest::wasmBytes(const std::vector &data, + std::string hash) { + Manifest m; + m.addWasmBytes(data, std::move(hash)); return m; } // Add Wasm from path void Manifest::addWasmPath(std::string s, std::string hash) { - Wasm w = Wasm::path(s, hash); - this->wasm.push_back(w); + Wasm w = Wasm::path(std::move(s), std::move(hash)); + this->wasm.push_back(std::move(w)); } // Add Wasm from URL void Manifest::addWasmURL(std::string u, std::string hash) { - Wasm w = Wasm::url(u, hash); - this->wasm.push_back(w); + Wasm w = Wasm::url(std::move(u), std::move(hash)); + this->wasm.push_back(std::move(w)); +} + +// add Wasm from bytes +void Manifest::addWasmBytes(const uint8_t *data, const size_t len, + std::string hash) { + Wasm w = Wasm::bytes(data, len, std::move(hash)); + this->wasm.push_back(std::move(w)); +} + +void Manifest::addWasmBytes(const std::vector &data, + std::string hash) { + Wasm w = Wasm::bytes(data, std::move(hash)); + this->wasm.push_back(std::move(w)); } // Add host to allowed hosts void Manifest::allowHost(std::string host) { - if (this->allowedHosts.empty()) { - this->allowedHosts.set(std::vector{}); - } - this->allowedHosts.value.push_back(host); + this->allowedHosts.push_back(std::move(host)); } // Add path to allowed paths void Manifest::allowPath(std::string src, std::string dest) { - if (this->allowedPaths.empty()) { - this->allowedPaths.set(std::map{}); - } - if (dest.empty()) { dest = src; } - this->allowedPaths.value[src] = dest; + this->allowedPaths[std::move(src)] = std::move(dest); } // Set timeout in milliseconds void Manifest::setTimeout(uint64_t ms) { this->timeout = ms; } // Set config key/value -void Manifest::setConfig(std::string k, std::string v) { this->config[k] = v; } +void Manifest::setConfig(std::string k, std::string v) { + this->config[std::move(k)] = std::move(v); +} }; // namespace extism diff --git a/src/plugin.cpp b/src/plugin.cpp index b1068f4..8620056 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -1,18 +1,23 @@ #include "extism.hpp" +#include namespace extism { -Plugin::Plugin(const uint8_t *wasm, ExtismSize length, bool withWasi, +void extism::Plugin::PluginDeleter::operator()(ExtismPlugin *plugin) const { + extism_plugin_free(plugin); +} + +Plugin::Plugin(const uint8_t *wasm, size_t length, bool withWasi, std::vector functions) - : functions(functions) { + : functions(std::move(functions)) { std::vector 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(), - withWasi, &errmsg); + this->plugin = unique_plugin(extism_plugin_new( + wasm, length, ptrs.data(), ptrs.size(), withWasi, &errmsg)); if (this->plugin == nullptr) { std::string s(errmsg); extism_plugin_new_error_free(errmsg); @@ -20,28 +25,26 @@ Plugin::Plugin(const uint8_t *wasm, ExtismSize length, bool withWasi, } } -Plugin::Plugin(const std::string &str, bool withWasi, +Plugin::Plugin(std::string_view str, bool withWasi, std::vector functions) - : Plugin((const uint8_t *)str.c_str(), str.size(), withWasi, functions) {} + : Plugin(reinterpret_cast(str.data()), str.size(), + withWasi, std::move(functions)) {} Plugin::Plugin(const std::vector &data, bool withWasi, std::vector functions) - : Plugin(data.data(), data.size(), withWasi, functions) {} + : Plugin(data.data(), data.size(), withWasi, std::move(functions)) {} Plugin::CancelHandle Plugin::cancelHandle() { - return CancelHandle(extism_plugin_cancel_handle(this->plugin)); + return CancelHandle(extism_plugin_cancel_handle(this->plugin.get())); } // Create a new plugin from Manifest Plugin::Plugin(const Manifest &manifest, bool withWasi, std::vector functions) - : Plugin(manifest.json().c_str(), withWasi, functions) {} + : Plugin(manifest.json(), withWasi, std::move(functions)) {} -Plugin::~Plugin() { - if (this->plugin == nullptr) - return; - extism_plugin_free(this->plugin); - this->plugin = nullptr; +bool Plugin::CancelHandle::cancel() { + return extism_plugin_cancel(this->handle); } void Plugin::config(const Config &data) { @@ -57,24 +60,24 @@ void Plugin::config(const Config &data) { } void Plugin::config(const char *json, size_t length) { - bool b = extism_plugin_config(this->plugin, (const uint8_t *)json, length); + bool b = extism_plugin_config( + this->plugin.get(), reinterpret_cast(json), length); if (!b) { - const char *err = extism_plugin_error(this->plugin); + const char *err = extism_plugin_error(this->plugin.get()); throw Error(err == nullptr ? "Unable to update plugin config" : err); } } -void Plugin::config(const std::string &json) { - this->config(json.c_str(), json.size()); +void Plugin::config(std::string_view json) { + this->config(json.data(), json.size()); } // Call a plugin -Buffer Plugin::call(const std::string &func, const uint8_t *input, - ExtismSize inputLength) const { - int32_t rc = - extism_plugin_call(this->plugin, func.c_str(), input, inputLength); +Buffer Plugin::call(const char *func, const uint8_t *input, + size_t inputLength) const { + int32_t rc = extism_plugin_call(this->plugin.get(), func, input, inputLength); if (rc != 0) { - const char *error = extism_plugin_error(this->plugin); + const char *error = extism_plugin_error(this->plugin.get()); if (error == nullptr) { throw Error("extism_call failed"); } @@ -82,24 +85,51 @@ Buffer Plugin::call(const std::string &func, const uint8_t *input, throw Error(error); } - ExtismSize length = extism_plugin_output_length(this->plugin); - const uint8_t *ptr = extism_plugin_output_data(this->plugin); + ExtismSize length = extism_plugin_output_length(this->plugin.get()); + const uint8_t *ptr = extism_plugin_output_data(this->plugin.get()); return Buffer(ptr, length); } +// Call a plugin function with std::vector input +Buffer Plugin::call(const char *func, const std::vector &input) const { + return this->call(func, input.data(), input.size()); +} + +// Call a plugin function with string input +Buffer Plugin::call(const char *func, std::string_view input) const { + return this->call(func, reinterpret_cast(input.data()), + input.size()); +} + +// Call a plugin +Buffer Plugin::call(const std::string &func, const uint8_t *input, + size_t inputLength) const { + return this->call(func.c_str(), input, inputLength); +} + // Call a plugin function with std::vector input Buffer Plugin::call(const std::string &func, const std::vector &input) const { - return this->call(func, input.data(), input.size()); + return this->call(func.c_str(), input); } // Call a plugin function with string input -Buffer Plugin::call(const std::string &func, const std::string &input) const { - return this->call(func, (const uint8_t *)input.c_str(), input.size()); +Buffer Plugin::call(const std::string &func, std::string_view input) const { + return this->call(func.c_str(), input); +} + +// Returns true if the specified function exists +bool Plugin::functionExists(const char *func) const { + return extism_plugin_function_exists(this->plugin.get(), func); } // Returns true if the specified function exists bool Plugin::functionExists(const std::string &func) const { - return extism_plugin_function_exists(this->plugin, func.c_str()); + return extism_plugin_function_exists(this->plugin.get(), func.c_str()); } + +// Reset the Extism runtime, this will invalidate all allocated memory +// returns true if it succeeded +bool Plugin::reset() const { return extism_plugin_reset(this->plugin.get()); } + }; // namespace extism