Skip to content

Commit

Permalink
cleanup: use input/output for host function arguments and results, cl…
Browse files Browse the repository at this point in the history
…eanup basic documentation (#5)
  • Loading branch information
zshipko authored Sep 22, 2023
1 parent d7372ab commit dcadd13
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 18 deletions.
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

0 comments on commit dcadd13

Please sign in to comment.