package DkSDKFFIOCaml_Std

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

Defining OCaml COM class objects

COM classes can be implemented in any DkSDK host platform.

The module ComClassBuilder lets you write classes in OCaml and register them so they can be accessed from any other DkSDK FFI platform (ex. DkSDK FFI Java).

Usage

Here is a minimal example that registers a COM class object:

open DkSDKFFIOCaml_Std
open ComStandardSchema.Make (ComMessage.C)
open Com.MakeClassBuilder (ComMessage.C)

let com = Com.create_c ()

let create_object return args =
  let number = Reader.Si32.(i1_get (of_message args)) in
  return (New
      (Printf.sprintf
      "instance constructed with create_object(args = %ld)"
      number))

let ask ~self return args =
  let question = Reader.St.(i1_get (of_message args)) in
  let ret =
    Printf.sprintf "I am an %s and I was asked: %s" self question
  in
  let bldr = Builder.St.(let r = init_root () in i1_set r ret; r) in
  return (Capnp bldr)

register com ~classname:"Basic::Question::Taker"
  [
    class_method ~name:"create_object" ~f:create_object ();
    instance_method ~name:"ask" ~f:ask ();
  ]

We can now use the Basic::Question::Taker COM class between programming languages linked into the same executable (ex. register a COM class in OCaml but use it in Java). DkSDK provides tools like DkSDK CMake to make it easy to link two programming languages into the same executable.

The coding patterns will look similar regardless of the programming language. Here we use the above registered COM class from OCaml itself:

open DkSDKFFIOCaml_Std

let com = Com.create_c ()

module BasicQuestionTaker = struct
  open ComStandardSchema.Make (ComMessage.C)
  let create com =
      Com.borrow_class_until_finalized com "Basic::Question::Taker"
  let method_create_object = Com.method_id "create_object"
  let method_ask = Com.method_id "ask"

  class questiontaker _clazz inst =
    object
      method ask question =
        let args =
          let open Builder.St in
          let rw = init_root () in i1_set rw question; to_message rw
        in
        let ret_ptr =
            Com.call_instance_method inst method_ask args
        in
        Reader.St.i1_get (Reader.of_pointer ret_ptr)
    end

  let new_questiontaker clazz number =
    let args =
      let open Builder.Si32 in
      let r = init_root () in i1_set_int_exn r number; to_message r
    in
    Com.call_class_constructor
      clazz method_create_object (new questiontaker clazz) args
end

let questiontaker_clazz = BasicQuestionTaker.create com
let questiontaker =
  BasicQuestionTaker.new_questiontaker questiontaker_clazz 37
let () = print_endline (questiontaker#ask "What am I?")

(* I am an instance constructed with create_object(args = 37)
   and I was asked: What am I? *)

Parameters

Signature

include sig ... end
type !'inst t_author = 'inst MakeReturn(M).t_author =
  1. | Capnp : (Capnp.Message.rw, 'struct_t) M.StructStorage.t -> 'a t_author
  2. | New : 'inst0 -> 'inst1 t_author

The type of value that will be given to a return function, which is the API expected to be used by authors of DkSDK COM classes. The return value is either a single Cap n' Proto message of type Capnp 'builder, or a new instance of type New 'ret_inst. The type parameter 'inst is the type of the generic instance object whose method was called.

type (!'inst0, 'ret_inst0) return = 'inst t_author -> (Capnp.Message.rw M.Message.t, Capnp.Message.ro M.Slice.t option, 'inst, 'ret_inst) t_return

The type of a function that can convert author-friendly t_author values into the t type needed by the DkSDK FFI APIs.

val return_from_closure : (Capnp.Message.rw, 'struct_t) M.StructStorage.t -> (Capnp.Message.rw M.Message.t, Capnp.Message.ro M.Slice.t option, 'a, 'b) t_return

The return value of a Com.closure

Types

type 'inst generic_component

The type of a component (interface, method, destructor), where one or more components constitutes a class.

Type parameter 'inst is the type of the instance.

Class Registration

val register : (Capnp.Message.rw M.Message.t, Capnp.Message.ro M.Slice.t option) t -> classname:string -> ?class_fallback_dtor: (Capnp.Message.rw M.Message.t -> Capnp.Message.rw M.Message.t) -> ?instance_fallback_dtor: (self:'inst -> Capnp.Message.rw M.Message.t -> Capnp.Message.rw M.Message.t) -> 'inst generic_component list -> unit

register com ~classname ?class_fallback_dtor ?instance_fallback_dtor [component1; component2; ...] builds a class named classname from a builder and a list of one or more components, and registers it as a COM object within DkSDK FFI.

If instance_fallback_dtor is specified, it will be the destructor used for instances when an explicit instance destructor is not called.

If class_fallback_dtor is specified, it will be the destructor used for classes when an explicit class destructor is not called. Typically these class destructors are only called when OCaml is shutting down.

Class Components

val class_method : name:string -> f: (('inst, 'ret_inst) return -> Capnp.Message.rw M.Message.t -> (Capnp.Message.rw M.Message.t, Capnp.Message.ro M.Slice.t option, 'inst, 'ret_inst) t_return) -> unit -> 'inst generic_component

class_method ~name ~f () adds an class method named name that will execute f when it is called.

f return args must use return to return either a Cap n' Proto message or a new instance, as in let f return args = return (Msg (*...*)) or let f return args = return (New (*...*)).

If the return value is a New instance, the return value will be bound to self of any instance_method or instance_destructor invocation that uses the new instance.

val class_destructor : name:string -> f:(Capnp.Message.rw M.Message.t -> Capnp.Message.rw M.Message.t) -> unit -> 'inst generic_component

class_destructor ~name ~f () adds an class destructor named name that will execute f when it is called.

The class destructors are registered with an OCaml at_exit handler, which will be invoked during a graceful OCaml shutdown. However, there is no guarantee of a graceful OCaml shutdown, so class destructors are not guaranteed to be called.

f args must return a Cap n' Proto message.

val instance_method : name:string -> f: (self:'inst -> ('inst, 'ret_inst) return -> Capnp.Message.rw M.Message.t -> (Capnp.Message.rw M.Message.t, Capnp.Message.ro M.Slice.t option, 'inst, 'ret_inst) t_return) -> unit -> 'inst generic_component

instance_method ~name ~f () adds an instance method named name and will execute f ~self return args when it is called.

f ~self return args must use return to return either a Cap n' Proto message or a new instance, as in let f ~self return args = return (Msg (*...*)) or let f ~self return args = return (New (*...*)).

If the return value is a New instance, the return value will be bound to self of any instance_method or instance_destructor invocation that uses the new instance.

val instance_destructor : name:string -> f: (self:'inst -> Capnp.Message.rw M.Message.t -> Capnp.Message.rw M.Message.t) -> unit -> 'inst generic_component

instance_destructor ~name ~f () adds an instance destructor named name that will execute f when it is called.

f ~self:inst args must return a Cap n' Proto message.

val abstract_instance_method : name:string -> unit -> 'inst generic_component

abstract_instance_method ~name () adds an abstract instance method named name that most be implemented by subclasses.

val abstract_instance_destructor : name:string -> unit -> 'inst generic_component

abstract_instance_destructor ~name () adds an abstract instance destructor named name that most be implemented by subclasses.

val interface : name:string -> unit -> 'inst generic_component

interface ~name () adds an abstract instance destructor named name that most be implemented by subclasses.

OCaml

Innovation. Community. Security.