Подтвердить что ты не робот

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
4b9b3361

Ответ 1

Похоже, ваш код работает и идиоматичен. Существует два способа представления ошибок:

  • вы можете создать исключение.
  • вы можете использовать тип результата. Если вы это сделаете, я бы рекомендовал использовать "новый" встроенный тип result (который был backported для более старых версий OCaml в result).

Вообще говоря, вы несете ответственность за написание кода, который поддерживает это соглашение об ошибках (часть match err в вашем коде). Часто можно написать пару комбинаторов для уменьшения шаблона.

Однако есть несколько ярлыков, предоставляемых ctypes, если вы используете Cstubs (генерация кода):

  • errno_policy может реализовать соглашение libc errno.
  • concurrency_policy может настраивать код C так, чтобы он соответствовал заданной модели concurrency (lwt и т.д.). Речь идет не о соглашениях об ошибках, а о некоторых отношениях.

Если вы придерживаетесь Foreign (что делает вашу систему сборки более простой, чем Cstubs), я бы рекомендовал сделать это вручную или извлечь пару комбинаторов, если у вас много подобных функций.