OCaml ctypes - идиоматический способ устранения параметров
Я пишу OCaml-обертки для нескольких функций C, которые используют идиому out-parameter и возвращают код ошибки. Я обернул их, выделив массив C на стороне OCaml, используя Ctypes.allocate_n
. А затем скопируйте содержимое в тип OCaml.
Я чувствую, что я взламываю проблему, что Ctypes
или какой-то другой модуль уже решает по-другому, вот пример.
gethostname(2)
имеет следующий тип:
int gethostname(char *name, size_t len);
Здесь out_parameter.mli
для обернутой функции gethostname
.
val gethostname : int -> [> `Ok of string | `Error of int];;
Здесь реализация
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 ();;
И для компиляции я скомпилировал out_parameter.native
с помощью этой команды.
$ corebuild -pkg ctypes.foreign out_parameter.native
Код действительно работает и возвращает имя хоста, с завершающим нулевым байтом.
$ ./out_parameter.native
MY-HOSTNAME
$ ./out_parameter.native | sed -e 's/\x0/@/g'
MY-HOSTNAME
Ответы
Ответ 1
Похоже, ваш код работает и идиоматичен. Существует два способа представления ошибок:
- вы можете создать исключение.
- вы можете использовать тип результата. Если вы это сделаете, я бы рекомендовал использовать "новый" встроенный тип
result
(который был backported для более старых версий OCaml в result).
Вообще говоря, вы несете ответственность за написание кода, который поддерживает это соглашение об ошибках (часть match err
в вашем коде). Часто можно написать пару комбинаторов для уменьшения шаблона.
Однако есть несколько ярлыков, предоставляемых ctypes
, если вы используете Cstubs
(генерация кода):
-
errno_policy
может реализовать соглашение libc errno
.
-
concurrency_policy
может настраивать код C так, чтобы он соответствовал заданной модели concurrency (lwt и т.д.). Речь идет не о соглашениях об ошибках, а о некоторых отношениях.
Если вы придерживаетесь Foreign
(что делает вашу систему сборки более простой, чем Cstubs
), я бы рекомендовал сделать это вручную или извлечь пару комбинаторов, если у вас много подобных функций.