From 478a2d510d54fa2e96b13ac227ec25a5b0e5e8d5 Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 21 Sep 2023 15:06:42 -0700 Subject: [PATCH 1/8] cleanup: use input/output for host function arguments and results --- lib/host_function.ml | 17 ++++++++--------- lib/plugin.ml | 4 ++-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/host_function.ml b/lib/host_function.ml index d32c0bf..71038b1 100644 --- a/lib/host_function.ml +++ b/lib/host_function.ml @@ -68,33 +68,32 @@ module Memory_handle = struct Bigstringaf.blit_from_string s ~src_off:0 x ~dst_off:0 ~len:length end -let result_string t ?(index = 0) s = +let output_string t ?(index = 0) s = let mem = Memory_handle.alloc t (String.length s) in Memory_handle.set_string t mem s; Val.Array.( t.results.$[index] <- Val.of_i64 (Unsigned.UInt64.to_int64 mem.offs)) -let result_bigstring t ?(index = 0) s = +let output_bigstring t ?(index = 0) s = let mem = Memory_handle.alloc t (Bigstringaf.length s) in Memory_handle.set_bigstring t mem s; Val.Array.( t.results.$[index] <- Val.of_i64 (Unsigned.UInt64.to_int64 mem.offs)) -let param_string ?(index = 0) t = +let input_string ?(index = 0) t = let inp = Val.Array.(t.params.$[index]) in let mem = Memory_handle.of_val_exn t inp in Memory_handle.get_string t mem -let param_bigstring ?(index = 0) t = +let input_bigstring ?(index = 0) t = let inp = Val.Array.(t.params.$[index]) in let mem = Memory_handle.of_val_exn t inp in Memory_handle.get_bigstring t mem -let result (type a) t ?index (module C : Type.S with type t = a) (a : a) = +let output (type a) t ?index (module C : Type.S with type t = a) (a : a) = let s = C.encode a in - print_endline s; - result_string t ?index s + output_string t ?index s -let param (type a) t ?index (module C : Type.S with type t = a) = - let bs = param_bigstring ?index t in +let input (type a) t ?index (module C : Type.S with type t = a) = + let bs = input_bigstring ?index t in C.decode bs diff --git a/lib/plugin.ml b/lib/plugin.ml index eb86ce8..944f8b9 100644 --- a/lib/plugin.ml +++ b/lib/plugin.ml @@ -134,11 +134,11 @@ let%test "call_functions" = Function.create "hello_world" ~params:[ I64 ] ~results:[ I64 ] ~user_data:"Hello again!" @@ fun plugin user_data -> - let s = Host_function.param plugin Type.string |> Result.get_ok in + let s = Host_function.input plugin Type.string |> Result.get_ok in let () = print_endline "Hello from OCaml!" in let () = print_endline user_data in let () = print_endline s in - Host_function.result plugin + Host_function.output plugin Type.json (`Assoc [ ("count", `Int 999) ]) in From 08ad0749a87c6a768c7199a11249e110d13afbab Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 21 Sep 2023 15:58:58 -0700 Subject: [PATCH 2/8] fix: update mli file --- lib/extism.mli | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/extism.mli b/lib/extism.mli index de9341a..279e214 100644 --- a/lib/extism.mli +++ b/lib/extism.mli @@ -132,25 +132,25 @@ module Host_function: sig type memory_handle = { offs : Unsigned.UInt64.t; len : Unsigned.UInt64.t } (** Represents a block of guest memory *) - val result_string : t -> ?index:int -> string -> unit + val output_string : t -> ?index:int -> string -> unit (** Return a string from a host function, this copies the string into memory and sets the results array at [index] with the pointer to the allocated value *) - val result_bigstring : t -> ?index:int -> Bigstringaf.t -> unit + val output_bigstring : t -> ?index:int -> Bigstringaf.t -> unit (** Return a bigstring from a host function, this copies the bigstring into memory and sets the results array at [index] with the pointer to the allocated value *) - val param_string : ?index:int -> t -> string + val input_string : ?index:int -> t -> string (** Get a string argument, the parameter at [index] should be an int64 value that points to the string in linear memory *) - val param_bigstring : ?index:int -> t -> Bigstringaf.t + val input_bigstring : ?index:int -> t -> Bigstringaf.t (** Load a parameter directly from memory *) - val param : t -> ?index:int -> (module Type.S with type t = 'a) -> ('a, Error.t) result + val input : t -> ?index:int -> (module Type.S with type t = 'a) -> ('a, Error.t) result (** Get parameter from params array at [index] and return the converted result *) - val result : t -> ?index:int -> (module Type.S with type t = 'a) -> 'a -> unit + val output : t -> ?index:int -> (module Type.S with type t = 'a) -> 'a -> unit (** Convert a value, allocate it and update the results array at [index] *) (** Some helpter functions for reading/writing memory *) From edff1132ebc3f070715c97745216dc8fde0d7bc8 Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 21 Sep 2023 16:24:53 -0700 Subject: [PATCH 3/8] ci: add more caching --- .github/workflows/test.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ae48cb8..84011d4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,11 +20,21 @@ jobs: with: dune-cache: true ocaml-compiler: "5.x" + - run: ocamlc -version > .ocaml-version + - name: Cache OCaml + id: cache-ocaml + uses: actions/cache@v3 + with: + path: _opam + key: ${{ runner.os }}-opam-${{ hashFiles('*.opam') }}-${{ hashFiles('dune-project') }}-${{ hashFiles('.ocamlversion') }} - name: Build OCaml Host SDK + if: steps.cache-ocaml.outputs.cache-hit != 'true' run: | + opam upgrade -y opam install -y --deps-only . LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune build - name: Test OCaml Host SDK run: | + opam upgrade -y 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 From f9611e4239fb8ba2aad6e507e22d54ecfb6d8044 Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 21 Sep 2023 16:31:09 -0700 Subject: [PATCH 4/8] ci: use matrix for compiler versions --- .github/workflows/test.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 84011d4..ac529db 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] + compiler: ["5.1"] steps: - name: Checkout sources uses: actions/checkout@v3 @@ -19,14 +20,14 @@ jobs: uses: ocaml/setup-ocaml@v2 with: dune-cache: true - ocaml-compiler: "5.x" + ocaml-compiler: ${{ matrix.compiler }} - run: ocamlc -version > .ocaml-version - name: Cache OCaml id: cache-ocaml uses: actions/cache@v3 with: path: _opam - key: ${{ runner.os }}-opam-${{ hashFiles('*.opam') }}-${{ hashFiles('dune-project') }}-${{ hashFiles('.ocamlversion') }} + key: ${{ runner.os }}-opam-${{ hashFiles('*.opam') }}-${{ hashFiles('dune-project') }}-${{ hashFiles('.ocaml-version') }} - name: Build OCaml Host SDK if: steps.cache-ocaml.outputs.cache-hit != 'true' run: | From 2617de934734c2a2c99d95d596aa8a3cc2e7f5a4 Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 21 Sep 2023 16:34:18 -0700 Subject: [PATCH 5/8] ci --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ac529db..3ca1769 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: with: dune-cache: true ocaml-compiler: ${{ matrix.compiler }} - - run: ocamlc -version > .ocaml-version + - run: opam exec -- ocamlc -version > .ocaml-version - name: Cache OCaml id: cache-ocaml uses: actions/cache@v3 From 1860e55361b27440681baa12a8bf1a12ee5959bd Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 21 Sep 2023 16:55:45 -0700 Subject: [PATCH 6/8] ci --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3ca1769..12457f7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - compiler: ["5.1"] + compiler: [ "5.1" ] steps: - name: Checkout sources uses: actions/checkout@v3 From ead9a271a757288650eaef2fa07dfa53b403b238 Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 21 Sep 2023 17:05:47 -0700 Subject: [PATCH 7/8] doc: cleanup docs a little --- .github/actions/libextism/action.yml | 2 ++ lib/extism.mli | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/.github/actions/libextism/action.yml b/.github/actions/libextism/action.yml index cd36dc2..72e50dc 100644 --- a/.github/actions/libextism/action.yml +++ b/.github/actions/libextism/action.yml @@ -13,3 +13,5 @@ runs: - name: Install shell: bash run: sudo extism lib install --version git + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/lib/extism.mli b/lib/extism.mli index 279e214..36bc2b8 100644 --- a/lib/extism.mli +++ b/lib/extism.mli @@ -5,13 +5,19 @@ val extism_version : unit -> string module Manifest = Extism_manifest +(** Extism error type *) module Error : sig type t = [ `Msg of string ] + (** Error type *) exception Error of t + (** Exception type *) val unwrap : ('a, t) result -> 'a + (** Like {!Result.get_ok} for {!t} *) + val throw : t -> 'a + (** Raise [t] as an exception *) end @@ -103,18 +109,37 @@ module Type: sig type t val encode : t -> string + (** Encode a value to a string *) + val decode : Bigstringaf.t -> (t, Error.t) result + (** Decode a value from a bigstring. The bigstring argument uses a direct pointer + into the plugin memory, this means it shouldn't be stored outside of this function + without being copied first *) end module String : S with type t = string + (** String type *) + module Bytes : S with type t = bytes + (** Bytes type *) + module Bigstring : S with type t = Bigstringaf.t + (** Bigstring type *) + module Json : S with type t = Yojson.Safe.t + (** Json type *) val string : (module S with type t = string) + (** String type helper, this can be passed to a function expecting a wrapped module *) + val bytes : (module S with type t = bytes) + (** Bytes type helper, this can be passed to a function expecting a wrapped module *) + val bigstring : (module S with type t = Bigstringaf.t) + (** Bigstring type helper, this can be passed to a function expecting a wrapped module *) + val json : (module S with type t = Yojson.Safe.t) + (** Json type helper, this can be passed to a function expecting a wrapped module *) end (** [Host_function] represents the plugin that is currently running, it should @@ -219,6 +244,7 @@ end val set_log_file : ?level:[ `Error | `Warn | `Info | `Debug | `Trace ] -> string -> bool +(** Set the log file and level for all Extism plugins *) (** [Plugins] contain functions that can be called *) module Plugin : sig From 0660e09c8cb36d4d0db0242bece61ea8876745b7 Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 21 Sep 2023 17:08:41 -0700 Subject: [PATCH 8/8] ci --- .github/actions/libextism/action.yml | 2 -- .github/workflows/test.yml | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/libextism/action.yml b/.github/actions/libextism/action.yml index 72e50dc..cd36dc2 100644 --- a/.github/actions/libextism/action.yml +++ b/.github/actions/libextism/action.yml @@ -13,5 +13,3 @@ runs: - name: Install shell: bash run: sudo extism lib install --version git - env: - GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 12457f7..ea06250 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,6 +16,8 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - uses: ./.github/actions/libextism + env: + GITHUB_TOKEN: ${{ github.token }} - name: Setup OCaml env uses: ocaml/setup-ocaml@v2 with: