I'm writing OCaml wrappers for a few C functions that use the out-parameter idiom and return an error code. I've been wrapping them by allocating a C array on the OCaml side using Ctypes.allocate_n. And then copying the contents out into an OCaml type.
I feel like I'm hacking around a problem that Ctypes or some other module already solves in another way, here's an example.
gethostname(2) has the following type:
int gethostname(char *name, size_t len);
Here's out_parameter.mli for the wrapped gethostname function.
val gethostname : int -> [> `Ok of string | `Error of int];;
Here's the implementation
open Core.Std;;
let (@->) = Ctypes.(@->);;
let returning = Ctypes.returning;;
open Foreign;;
let gethostname size =
let size' = Unsigned.Size_t.of_int size in
let c_gethostname =
foreign "gethostname" (Ctypes.ptr Ctypes.char @-> Ctypes.size_t @-> returning Ctypes.int) in
let buf = Ctypes.allocate_n Ctypes.char ~count:size in
let err = c_gethostname buf size' in
match err with
| 0 -> (
`Ok (Ctypes.string_from_ptr buf ~length:size)
)
| _ -> `Error err;;
let main () =
Printf.printf "%s\n" (match gethostname 1000 with
| `Ok hostname -> hostname
| `Error _ -> "error getting hostname");;
let () = main ();;
And for the sake of compeleteness I compiled out_parameter.native with this command.
$ corebuild -pkg ctypes.foreign out_parameter.native
The code does work and returns the hostname, with trailing null bytes stripped.
$ ./out_parameter.native
MY-HOSTNAME
$ ./out_parameter.native | sed -e 's/\x0/@/g'
MY-HOSTNAME
It looks like your code works and is idiomatic. There are two ways to represent errors:
result type (that has been backported for older versions of OCaml in the result package).Generally speaking, you are responsible for writing code that supports that error convention (the match err part in your code). It is often possible to write a couple combinators to reduce the boilerplate.
However, there are a couple shortcuts provided by ctypes if you use Cstubs (code generation):
errno_policy can implement libc's errno convention.concurrency_policy can tune the C code so that it correspond to a given concurrency model (lwt, etc). This is not about error conventions, but is somewhat related.If you stick to Foreign (which makes your build system simpler than Cstubs), then I'd recommend doing it by hand, or extracting a couple combinators if you have a lot of similar functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With