Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cleanup: use input/output for host function arguments and results, cleanup basic documentation #5

Merged
merged 8 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,33 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
compiler: [ "5.1" ]
steps:
- 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:
dune-cache: true
ocaml-compiler: "5.x"
ocaml-compiler: ${{ matrix.compiler }}
- run: opam exec -- 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('.ocaml-version') }}
- 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
38 changes: 32 additions & 6 deletions lib/extism.mli
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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
Expand All @@ -132,25 +157,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 *)
Expand Down Expand Up @@ -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
Expand Down
17 changes: 8 additions & 9 deletions lib/host_function.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions lib/plugin.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading