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