package ctypes

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file cstubs_inverted.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
(*
 * Copyright (c) 2014 Jeremy Yallop.
 *
 * This file is distributed under the terms of the MIT License.
 * See the file LICENSE for details.
 *)

(* Cstubs_inverted public interface. *)

[@@@warning "-9-27"]

module type INTERNAL =
sig
  val enum : (string * int64) list -> 'a Ctypes.typ -> unit
  val structure : _ Ctypes.structure Ctypes.typ -> unit
  val union : _ Ctypes.union Ctypes.typ -> unit
  val typedef : _ Ctypes.typ -> string -> unit

  val internal : ?runtime_lock:bool -> string -> ('a -> 'b) Ctypes.fn -> ('a -> 'b) -> unit
end

module type BINDINGS = functor (F : INTERNAL) -> sig end

type fn_meta = {
  fn_runtime_lock : bool;
  fn_name         : string;
}
type fn_info = Fn : fn_meta * (_ -> _) Ctypes.fn -> fn_info
type ty = Ty : _ Ctypes.typ -> ty
type typedef = Typedef : _ Ctypes.typ * string -> typedef
type enum = Enum : (string * int64) list * _ Ctypes.typ -> enum
type decl =
    Decl_fn of fn_info
  | Decl_ty of ty
  | Decl_typedef of typedef
  | Decl_enum of enum

let functions decls =
  List.concat (List.map (function Decl_fn fn -> [fn] | _ -> []) decls)

let collector () : (module INTERNAL) * (unit -> decl list) =
  let decls = ref [] in
  let push d = decls := d :: !decls in
  ((module
    struct
      let enum constants typ = push (Decl_enum (Enum (constants, typ)))
      let structure typ = push (Decl_ty (Ty typ))
      let union typ = push (Decl_ty (Ty typ))
      let typedef typ name = push (Decl_typedef (Typedef (typ, name)))
      let internal ?(runtime_lock=false) name fn _ =
        let meta = { fn_runtime_lock = runtime_lock; fn_name = name } in
        push (Decl_fn ((Fn (meta, fn))))
    end),
   (fun () -> List.rev !decls))

let format_enum_values fmt infos =
  List.iter (fun (Fn ({fn_name}, _)) -> Format.fprintf fmt "@[fn_%s,@]@ " fn_name) infos

let c_prologue fmt register infos =
  Format.fprintf fmt "#include <caml/memory.h>@\n";
  Format.fprintf fmt "#include <caml/callback.h>@\n";
  Format.fprintf fmt "#include \"ctypes_cstubs_internals.h\"@\n@\n";
  Format.fprintf fmt "enum functions@\n{@[<v 2>@ %afn_count@]@\n};"
    format_enum_values infos;
  Format.fprintf fmt "@\n
/* A table of OCaml \"callbacks\". */
static value functions[fn_count];

/* Record a value in the callback table. */
value %s(value i, value v)
{
  CAMLparam2(i, v);
  functions[Long_val(i)] = v;
  caml_register_global_root(&functions[Long_val(i)]);
  CAMLreturn (Val_unit);
}@\n" register

let c_function fmt (Fn ({fn_name; fn_runtime_lock}, fn)) : unit =
  Cstubs_generate_c.inverse_fn ~stub_name:fn_name ~runtime_lock:fn_runtime_lock fmt fn

let gen_c fmt register infos =
  begin
    c_prologue fmt register infos;
    List.iter (c_function fmt) infos
  end

let c_declaration fmt (Fn ({fn_name; fn_runtime_lock}, fn)) : unit =
  Cstubs_generate_c.inverse_fn_decl ~stub_name:fn_name fmt fn

let write_structure_declaration fmt (Ty ty) =
  Format.fprintf fmt "@[%a@];@\n@\n" (fun ty -> Ctypes.format_typ ty) ty

let write_enum_declaration fmt (Enum (constants, ty)) =
  Format.fprintf fmt "@[%a@ {@\n@[<v 2>@\n" (fun ty -> Ctypes.format_typ ty) ty;
  let last = List.length constants - 1 in
  List.iteri
    (fun i (name, value) ->
       (* Trailing commas are not allowed. *)
       if i < last
       then Format.fprintf fmt "@[%s@ =@ %Ld,@]@\n" name value
       else Format.fprintf fmt "@[%s@ =@ %Ld@]@\n" name value)
    constants;
  Format.fprintf fmt "@]@]@\n};@\n@\n"

let write_typedef fmt (Typedef (ty, name)) =
  let write_name _ fmt = Format.fprintf fmt "@ %s" name in
  Format.fprintf fmt "@[typedef@ @[";
  Ctypes_type_printing.format_typ' ty write_name `nonarray fmt;
  Format.fprintf fmt "@]@];@\n@\n"

let write_declaration fmt = function
    Decl_fn f -> c_declaration fmt f
  | Decl_ty s -> write_structure_declaration fmt s
  | Decl_typedef t -> write_typedef fmt t
  | Decl_enum e -> write_enum_declaration fmt e

let write_c fmt ~prefix (module B : BINDINGS) : unit =
  let register = prefix ^ "_register" in
  let m, decls = collector () in
  let module M = B((val m)) in
  gen_c fmt register (functions (decls ()));
  Format.fprintf fmt "@."

let write_c_header fmt ~prefix (module B : BINDINGS) : unit =
  let m, decls = collector () in
  let module M = B((val m)) in
  List.iter (write_declaration fmt) (decls ());
  Format.fprintf fmt "@."

let gen_ml fmt register (infos : fn_info list) : unit =
  Format.fprintf fmt
    "type 'a fn = 'a@\n@\n";
  Format.fprintf fmt
    "module CI = Cstubs_internals@\n@\n";
  Format.fprintf fmt "type 'a f = 'a CI.fn =@\n";
  Format.fprintf fmt " | Returns  : 'a CI.typ   -> 'a f@\n";
  Format.fprintf fmt " | Function : 'a CI.typ * 'b f  -> ('a -> 'b) f@\n";
  Format.fprintf fmt
    "type 'a name = @\n";
  ListLabels.iter infos
    ~f:(fun (Fn ({fn_name}, fn)) ->
        Cstubs_generate_ml.constructor_decl ~concurrency:`Sequential
          ~errno:`Ignore_errno
          (Printf.sprintf "Fn_%s" fn_name) fn fmt);
  Format.fprintf fmt
    "@\n";
  Format.fprintf fmt
    "@[<h>external register_value : 'a name -> 'a fn -> unit =@\n@ @ \"%s\"@]@\n@\n"
    register;
  Format.fprintf fmt
    "@[<h>let internal : ";
  Format.fprintf fmt
    "@[type a b.@ @[?runtime_lock:bool -> string -> (a -> b) Ctypes.fn -> (a -> b) -> unit@]@]@ =@\n";
  Format.fprintf fmt
    "fun ?runtime_lock name fn f -> match fn, name with@\n@[";
  ListLabels.iter infos
    ~f:(fun (Fn ({fn_name}, fn)) ->
      Cstubs_generate_ml.inverse_case ~register_name:"register_value"
        ~constructor:(Printf.sprintf "Fn_%s" fn_name) fn_name fmt fn);
  Format.fprintf fmt
    "| _ -> failwith (\"Linking mismatch on name: \" ^ name)@]@]@]@\n@\n";
  Format.fprintf fmt
    "let enum _ _ = () and structure _ = () and union _ = () and typedef _ _ = ()@."

let write_ml fmt ~prefix (module B : BINDINGS) : unit =
  let register = prefix ^ "_register" in
  let m, decls = collector () in
  let module M = B((val m)) in
  gen_ml fmt register (functions (decls ()))
OCaml

Innovation. Community. Security.