dksdk_ffi_c/cls_generic.h

Defines

DK_CLS_MAX_FAT_POINTER_SZ
DK_CLS_ERR_DEAD_OBJECT

The object was dead due to a destructor call, yet an instance method was called.

DK_IIDSTR_GENERIC_CLASS

The interface identifier for the class object dksdk_ffi_c_cls_generic.

Typedefs

typedef uint32_t meth31

A method identifier.

typedef int DK_MESSAGE_BUILDER(struct dksdk_ffi *ffi, struct capn *messageAddr)

Create a message that can be used to build a return value message from a method call, or an arguments message to a method call.

Param ffi:

[in] The FFI pointer from dksdk_ffi_host_create

Param messageAddr:

The address of a struct capn that, on success, will be set to the the newly constructed message.

Return:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi or messageAddr are NULL

  • DKSDK_FFI_ERR_INVALID_STATE when there is not enough memory

typedef int DK_CLASS_METHOD(struct dksdk_ffi *ffi, struct dksdk_ffi_c_cls_generic_class_fields *ctor, const struct dksdk_ffi_c_cls_closure_data *closure, struct dksdk_ffi_c_cls_generic_call_ctx *ctx, struct dk_cls_capnp_args *args)

A class (also known as static) method, including but not limited to a class constructor method.

The return value for the class method must comply with Returning results from methods.

Requirements

  1. The class method has a post-condition. It must release the args parameter with dksdk_ffi_c_cls_release_args, even if the method exited in error.

  2. The args parameter must not be released before the arguments have been parsed and used.

The timing of the dksdk_ffi_c_cls_release_args can be done whenever it is convenient. Choices include:

  • Releasing before the method exits

  • If the method queues up work in an event queue, releasing when the work is removed from the event queue

Param ffi:

[in] The FFI pointer from dksdk_ffi_host_create

Param ctor:

[in] A constructor helper object. If the method is a constructor method, this constructor helper object can be used in dksdk_ffi_c_cls_generic_new_instance to create a new instance.

Param closure:

[in] Closure captured when the class method was defined.

Param ctx:

[in] Context for the call, including a message for a return value. The return value is an already initialized Cap n' Proto message. As an optimization the return value message may have one or more of its segments pre-allocated on the stack. Some messages may not let you exceed the capacity of pre-allocated segments; if so, you must return DKSDK_FFI_ERR_INVALID_STATE.

Param args:

[in] Cap n' Proto message whose root structure contains the arguments for the method. May be NULL.

Return:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT on error

  • DKSDK_FFI_ERR_INVALID_STATE on error

  • any positive, non-zero number for a user error code

typedef int DK_CLASS_DESTRUCTOR(struct dksdk_ffi *ffi, const struct dksdk_ffi_c_cls_closure_data *closure, const dksdk_ffi_uuid *clsid, struct dk_cls_capnp_args *args)

A destructor on an class.

Once a destructor is called, it is DkSDK FFI's responsibility to ensure no other destructor method will be called again for that class. In other words, the destructor is idempotent and will not create a double free bug. When a second destructor is called (or the same destructor is called twice), DkSDK FFI will ignore the second destructor call.

Requirements

  1. The instance method has a post-condition. It must release the args parameter with dksdk_ffi_c_cls_release_args, even if the method exited in error.

  2. The args parameter must not be released before the arguments have been parsed and used.

The timing of the dksdk_ffi_c_cls_release_args can be done whenever it is convenient. Choices include:

  • Releasing before the method exits

  • If the method queues up work in an event queue, releasing when the work is removed from the event queue

Why Destructor Arguments?

Although it is unusual for a programming language to have destructor arguments, DkSDK FFI's API mandates that arguments are passed to destructors. That is because method identifiers have a broad range and can map to destructors, instance methods or other types of methods. When you allocate method arguments something (the method, including destructor method) is responsible for de-allocating those arguments.

Param ffi:

[in] The FFI pointer from dksdk_ffi_host_create

Param closure:

[in] Closure captured when the class destructor was defined.

Param clsid:

[in] The CLSID that is being destroyed.

Param args:

[in] Cap n' Proto message whose root structure contains the arguments for the destructor method. May be NULL.

Return:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT on error

  • DKSDK_FFI_ERR_INVALID_STATE on error

  • any positive, non-zero number for a user error code

typedef int DK_INSTANCE_METHOD(struct dksdk_ffi *ffi, struct dksdk_ffi_c_cls_generic_instance *instance, const struct dksdk_ffi_c_cls_closure_data *closure, struct dksdk_ffi_c_cls_generic_call_ctx *ctx, struct dk_cls_capnp_args *args)

A method on an instance object.

The return value for the instance method must comply with Returning results from methods.

Requirements

  1. The instance method has a post-condition. It must release the args parameter with dksdk_ffi_c_cls_release_args, even if the method exited in error.

  2. The args parameter must not be released before the arguments have been parsed and used.

The timing of the dksdk_ffi_c_cls_release_args can be done whenever it is convenient. Choices include:

  • Releasing before the method exits

  • If the method queues up work in an event queue, releasing when the work is removed from the event queue

See also

DK_CLASS_METHOD

Param ffi:

[in] The FFI pointer from dksdk_ffi_host_create

Param instance:

[in] The instance values of the instance object. Its ptr field has the pointer to the host object. The lifetime of instance is only to the end of the instance method.

Param closure:

[in] Closure captured when the instance method was defined.

Param ctx:

[in] Context for the call, including a message for a return value. The return value is an already initialized Cap n' Proto message. As an optimization the return value message may have one or more of its segments pre-allocated on the stack. Some messages may not let you exceed the capacity of pre-allocated segments; if so, you must return DKSDK_FFI_ERR_INVALID_STATE.

Param args:

[in] Cap n' Proto message whose root structure contains the arguments for the method. May be NULL.

Return:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT on error

  • DKSDK_FFI_ERR_INVALID_STATE on error

  • DK_CLS_ERR_DEAD_OBJECT if there was a prior destructor call

  • any positive, non-zero number for a user error code

typedef int DK_INSTANCE_DESTRUCTOR(struct dksdk_ffi *ffi, struct dksdk_ffi_c_cls_generic_instance *instance, const struct dksdk_ffi_c_cls_closure_data *closure, struct dk_cls_capnp_args *args)

A destructor on an instance.

Once a destructor is called, it is DkSDK FFI's responsibility to ensure no other destructor method will be called again for that instance. In other words, the destructor is idempotent and will not create a double free bug. When a second destructor is called (or the same destructor is called twice), DkSDK FFI will ignore the second destructor call.

Requirements

  1. The instance method has a post-condition. It must release the args parameter with dksdk_ffi_c_cls_release_args, even if the method exited in error.

  2. The args parameter must not be released before the arguments have been parsed and used.

The timing of the dksdk_ffi_c_cls_release_args can be done whenever it is convenient. Choices include:

  • Releasing before the method exits

  • If the method queues up work in an event queue, releasing when the work is removed from the event queue

Why Destructor Arguments?

Although it is unusual for a programming language to have destructor arguments, DkSDK FFI's API mandates that arguments are passed to destructors. That is because method identifiers have a broad range and can map to destructors, instance methods or other types of methods. When you allocate method arguments something (the method, including destructor method) is responsible for de-allocating those arguments.

Param ffi:

[in] The FFI pointer from dksdk_ffi_host_create

Param instance:

[in] The instance values of the instance object. Its ptr field has the pointer to the host object. The lifetime of instance is only to the end of the instance method.

Param closure:

[in] Closure captured when the instance destructor was defined.

Param args:

[in] Possibly null Cap n' Proto message whose root structure contains the arguments for the destructor method. May be NULL.

Return:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT on error

  • DKSDK_FFI_ERR_INVALID_STATE on error

  • any positive, non-zero number for a user error code

typedef size_t DK_INSTANCE_HEAP_SIZE(const struct dksdk_ffi *ffi, const struct dksdk_ffi_c_cls_generic_instance *instance)

A function to over-estimate how much heap RAM is consumed by an instance object.

Param ffi:

[in] The FFI pointer from dksdk_ffi_host_create

Param instance:

[in] The instance values of the instance object. Its ptr field has the pointer to the host object. The lifetime of instance is only to the end of the heap size call.

typedef int METHOD_DISPATCH(struct dksdk_ffi *ffi, struct dksdk_ffi_c_cls_generic *generic, struct dksdk_ffi_c_cls_generic_call_ctx *ctx, meth31 method31, struct dk_cls_capnp_args *args)

A function that routes to a specific method on an object.

The args parameter has move semantics. Ownership transfers to this function, even if there is an error. This function will, at some point, dksdk_ffi_release the args:

  • If there is an error, the release is immediate

  • When the method is finished with the method arguments, the method must do the release

Param ffi:

[in] The FFI pointer from dksdk_ffi_host_create

Param generic:

[in] The generic class or instance object.

Param ctx:

[in] Context for the call, including a message for a return value. The return value is an already initialized Cap n' Proto message. As an optimization the return value message may have one or more of its segments pre-allocated on the stack. Some messages may not let you exceed the capacity of pre-allocated segments; if so, you must return DKSDK_FFI_ERR_INVALID_STATE.

Param method31:

[in] The 31-bit method identifier for the method name, obtained from dksdk_ffi_c_cls_generic_meth31.

Param args:

[in] Reference-counted Cap n' Proto message whose root structure contains the arguments for the method.

Return:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT on error

  • DKSDK_FFI_ERR_INVALID_STATE on error

  • DKSDK_FFI_ERR_NOT_FOUND when the method was not found

  • any positive, non-zero number for a user error code

typedef uint32_t iid31

The type for the hash of an interface identifier (IID).

Enums

enum dksdk_ffi_c_cls_generic_embedded_debug

Flags for whether debug information is embedded.

Values:

enumerator GENERIC_WITH_DEBUG
enumerator GENERIC_WITHOUT_DEBUG
enum dksdk_ffi_c_cls_generic_object_type

Whether the object is a class object or an instance object.

Values:

enumerator GENERIC_CLASS_OBJECT
enumerator GENERIC_INSTANCE_OBJECT
enum dksdk_ffi_c_cls_generic_component_type

The type of component that will be added to a class.

Values:

enumerator component_class_end
enumerator component_class_method
enumerator component_class_destructor
enumerator component_instance_method
enumerator component_instance_destructor
enumerator component_abstract_instance_method
enumerator component_abstract_instance_destructor
enumerator component_intf

Functions

static inline struct dksdk_ffi_c_cls_self_data dksdk_ffi_c_cls_self_data_from_void_pointer(void *ptr)
DKSDK_FFI_C_EXPORT int dksdk_ffi_c_cls_call_ctx_initial(struct dksdk_ffi *ffi, struct dksdk_ffi_c_cls_generic_call_ctx *ctxAddr)

Creates an initial context for one top-level (ie.

not nested) method call.

Typically you will want to allocate the struct dksdk_ffi_c_cls_generic_call_ctx as a local stack variable, and then call this function to initialize it. For example:

struct dksdk_ffi_c_cls_generic_call_ctx ctx;
ret = dksdk_ffi_c_cls_call_ctx_initial(ffi, &ctx);
if (ret != DKSDK_FFI_OK) return; // do something with error

However, you can do heap allocation for struct dksdk_ffi_c_cls_generic_call_ctx; it then would be your responsibility for de-allocating the struct.

After the call context is initialized:

  • you can set any of the flags like host_configured_for_call_chain or guest_configured_for_call_chain

It is your responsibility to call dksdk_ffi_c_cls_call_ctx_release_returnval after the call has been completed.

Parameters:
Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi, ctxAddr, or retValAddr are NULL

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_cls_call_ctx_nest(struct dksdk_ffi *ffi, struct dksdk_ffi_c_cls_call_ctx_params params)

Create a nested call context, where within a call context there is another call.

The typical usage is:

function callerScope() {
  struct dksdk_ffi_c_cls_generic_call_ctx callee_ctx;
  ret = dksdk_ffi_c_cls_call_ctx_nest(
     ffi,
     (struct dksdk_ffi_c_cls_call_ctx_params) {
       .callerPtr = &ctx,
       .calleeAddr = &callee_ctx});
  if (ret != DKSDK_FFI_OK) return; // do something with error

// ... do call to the callee ...

dksdk_ffi_c_cls_call_ctx_release_returnval(ffi, &callee_ctx);

// .. do more calls to more callees ... }

It is your responsibility to call dksdk_ffi_c_cls_call_ctx_release_returnval on the callee (calleeAddr) after you have used the return value from a successful (DKSDK_FFI_OK) nested call.

dksdk_ffi_c_cls_call_ctx_nest will automatically release the return value if there is an error.

Parameters:
  • ffi -- [in] The FFI pointer from dksdk_ffi_host_create

  • params -- [in] The parent and child context parameters

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi, or callerPtr or calleeAddr of params, are NULL

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_cls_call_ctx_tail(struct dksdk_ffi *ffi, struct dksdk_ffi_c_cls_call_ctx_params params)

Create a nested call context, where within a call context (the "caller") there a call (the "callee" call) in the tail position.

The typical usage is:

function callerScope(caller_ctx) {
  struct dksdk_ffi_c_cls_generic_call_ctx tailcall_ctx;
  ret = dksdk_ffi_c_cls_call_ctx_tail(
     ffi,
     (struct dksdk_ffi_c_cls_call_ctx_params) {
       .callerPtr = &ctx,
       .calleeAddr = &tailcall_ctx});
  if (ret != DKSDK_FFI_OK) return; // do something with error

// do call to callee ... dksdk_ffi_release(ffi, &callee_args->com);

return; }

Unlike dksdk_ffi_c_cls_call_ctx_nest you should not use dksdk_ffi_c_cls_call_ctx_release_returnval on the callee (calleeAddr). Instead the callee's return value message is the caller's return value message, so it will be the responsibility of the caller to release the return value.

Parameters:
  • ffi -- [in] The FFI pointer from dksdk_ffi_host_create

  • params -- [in] The parent and child context parameters

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi, or callerPtr or calleeAddr of params, are NULL

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_cls_call_ctx_release_returnval(struct dksdk_ffi *ffi, struct dksdk_ffi_c_cls_generic_call_ctx *ctxPtr)

Decrements the reference count of the call context's return_value message.

Do not use the call context after this operation.

Parameters:
Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi or ctxPtr is NULL

  • DKSDK_FFI_ERR_INVALID_STATE when the context was corrupted, possibly due to double release.

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_cls_release_args(struct dksdk_ffi *ffi, struct dk_cls_capnp_args *args)

Decrements the reference count of the method arguments.

Do not use the method arguments after this operation.

Parameters:
  • ffi -- [in] The FFI pointer from dksdk_ffi_host_create

  • args -- [in] Arguments to a method. May be NULL.

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi or args is NULL

  • DKSDK_FFI_ERR_INVALID_STATE when the arguments were corrupted, possibly due to double release.

DKSDK_FFI_C_EXPORT dksdk_ffi_uuid dksdk_ffi_c_cls_generic_iid_of_qualname(const char *fullyQualifiedName)

Get the class identifier (CLSID) or interface identifier (IID) of the fully qualified class or interface name.

The returned UUID will be the least significant bytes of the SHA-256 hash of the concatenation of the fully qualified UTF-8 encoded name and a constant.

Use a CLSID with dksdk_ffi_registry_get(ffi, CLSID, &classObject) to retrieve a Generic class object.

The UTF-8 encoding may not contain a NUL code point (the code point 0).

Parameters:

fullyQualifiedName -- [in] The name of the class or interface with :: as the namespace separator, like in C++. An example could be Stark::Accutech::BetaParticleGenerator. The CLSID will be deterministically derived from this fully qualified class name.

Returns:

dksdk_ffi_uuid The CLSID for the class name or IID for the interface name.

DKSDK_FFI_C_EXPORT iid31 dksdk_ffi_c_cls_generic_iid31_of_qualname(const char *fullyQualifiedName)

Get the 31-bit variant of the class identifier (CLSID) or interface identifier (IID) of the fully qualified class or interface name.

The 31-bit variant is the least significant 32 bits of the SHA256 hash of the concatenation of the fully qualified UTF-8 encoded name and a constant, with the least significant bit set to one (1). The integer representation of the hash bits is little endian.

The 31-bit variant is used in hash tables, and can also be used:

  • as a normal C uint32_t after shifting to the right one bit

  • as an unboxed OCaml signed integer, where the most significant bit is used as the sign bit in two's complement representation

  • as a v8 JavaScript small integer (Smi) after resetting the least significant bit to zero (0). See https://v8.dev/blog/pointer-compression

The UTF-8 encoding may not contain a NUL code point (the code point 0).

Parameters:

fullyQualifiedName -- [in] The name of the class or interface with :: as the namespace separator, like in C++. An example could be Stark::Accutech::BetaParticleGenerator. The CLSID will be deterministically derived from this fully qualified class name.

Returns:

uint32_t The 31-bit CLSID or IID expressed as an odd 32-bit number; the lowest bit will always be one (1).

DKSDK_FFI_C_EXPORT meth31 dksdk_ffi_c_cls_generic_meth31(const char *methodName)

Get the 31-bit method identifier.

Use the method identifier with (struct dksdk_ffi_c_cls_generic).method_dispatch to call a method.

The method identifier is the least significant 32 bits of the SHA256 of the concatenation of the UTF-8 encoded method name and a constant, with the least significant bit set to one (1).

The UTF-8 encoding may not contain a NUL code point (the code point 0).

See dksdk_ffi_c_cls_generic_iid31_of_qualname for how 31-bit numbers can be used.

Parameters:

methodName -- [in] The UTF-8 encoded name of the method.

Returns:

The method identifier

DKSDK_FFI_C_EXPORT int dk_add_class(struct dksdk_ffi *ffi, const char *fullyQualifiedClassName, DK_CLASS_DESTRUCTOR *classFallbackDtorMostlyRequired, struct dksdk_ffi_c_cls_closure_data classFallbackDtorClosure, DK_INSTANCE_HEAP_SIZE *heapSizeOverEstimator, DK_INSTANCE_DESTRUCTOR *instanceFallbackDtorMostlyRequired, struct dksdk_ffi_c_cls_closure_data instanceFallbackDtorClosure, ...)

Adds a class with all of its constructors, destructors, methods and interfaces.

The constructors, destructors and methods are supplied as individual parameters from builders of this header file, and must be terminated with DK_CLASS_END.

For example:

dk_add_class(ffi, "Posix::FILE::Readonly",
        &heap_size_over_estimator, &dtor, NO_CLOSURE,
        dk_abstract_instance_method("Read"),
        dk_abstract_instance_destructor("Close"),
        DK_CLASS_END);
dk_add_class(ffi, "Posix::FILE",
        &heap_size_over_estimator, &dtor, NO_CLOSURE,
        dk_class_method("Open", &do_fopen, NO_CLOSURE),
        dk_class_method("OpenForRead", &do_fopen_readonly, NO_CLOSURE),
        dk_instance_method("Read", &do_fread, NO_CLOSURE),
        dk_instance_method("Write", &do_fwrite, NO_CLOSURE),
        dk_instance_destructor("Close", &do_fclose, NO_CLOSURE),
        dk_interface("Posix::FILE::Readonly"),
        DK_CLASS_END);

A Generic interface is a set of methods with no constructors and destructors. When dk_add_class succeeds, both a class will be created with the name from fullyQualifiedClassName (ex. Posix::FILE) and a Generic interface will be created with the same name but with no constructors and destructors.

Using dk_interface you can register sub-interfaces that the class supports. The sub-interfaces must have been already registered using dk_add_class containing only abstract methods.

Parameters:
  • ffi -- [in] The FFI pointer from dksdk_ffi_host_create

  • fullyQualifiedClassName -- [in] The name of the class with :: as the namespace separator, like in C++. An example could be Stark::Accutech::BetaParticleGenerator. The CLSID will be deterministically derived from this fully qualified class name.

  • classFallbackDtorMostlyRequired -- [in] Required except when there are no class destructor components The fallback class destructor will be called when the number of references to any class object drops to zero, but no explicit class destructor has been called yet.

  • classFallbackDtorClosure -- [in] The closure passed to classFallbackDtorMostlyRequired. Use NO_CLOSURE if there is no classFallbackDtorMostlyRequired.

  • heapSizeOverEstimator -- [in] A function to calculate the heap size of the instance. If the function is an estimate, it should be an overestimate rather than an underestimate. If the instance takes no heap space, use zero_heap_size_estimator.

  • instanceFallbackDtorMostlyRequired -- [in] Required except when there are no instance destructor components The fallback instance destructor will be called when the number of references to any instance object drops to zero, but no explicit instance destructor has been called yet.

  • instanceFallbackDtorClosure -- [in] The closure passed to instanceFallbackDtorMostlyRequired. Use NO_CLOSURE if there is no instanceFallbackDtorMostlyRequired.

  • ... -- Zero or more slots (constructors, destructors and/or methods) of type struct dksdk_ffi_c_cls_generic_component.

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi or fullyQualifiedClassName is NULL.

  • DKSDK_FFI_ERR_INVALID_STATE when there is no more memory.

DKSDK_FFI_C_EXPORT int dk_xadd_class(struct dksdk_ffi *ffi, const char *fullyQualifiedClassName, DK_CLASS_DESTRUCTOR *classFallbackDtorMostlyRequired, struct dksdk_ffi_c_cls_closure_data classFallbackDtorClosure, DK_INSTANCE_HEAP_SIZE *heapSizeOverEstimator, DK_INSTANCE_DESTRUCTOR *instanceFallbackDtorMostlyRequired, struct dksdk_ffi_c_cls_closure_data instanceFallbackDtorClosure, size_t numComponents, const struct dksdk_ffi_c_cls_generic_component *components)

Non-variadic form of dk_add_class.

DK_CLASS_END must not be a component.

See also

dk_add_class

Parameters:
  • ffi -- [in] The FFI pointer from dksdk_ffi_host_create

  • fullyQualifiedClassName -- [in] The name of the class with :: as the namespace separator, like in C++. An example could be Stark::Accutech::BetaParticleGenerator. The CLSID will be deterministically derived from this fully qualified class name.

  • classFallbackDtorMostlyRequired -- [in] Required except when there are no class destructor components The fallback class destructor will be called when the number of references to any class object drops to zero, but no explicit class destructor has been called yet.

  • classFallbackDtorClosure -- [in] The closure passed to classFallbackDtorMostlyRequired. Use NO_CLOSURE if there is no classFallbackDtorMostlyRequired.

  • heapSizeOverEstimator -- [in] A function to calculate the heap size of the instance. If the function is an estimate, it should be an overestimate rather than an underestimate. If the instance takes no heap space, use zero_heap_size_estimator.

  • instanceFallbackDtorMostlyRequired -- [in] Required except when there are no instance destructor components The fallback instance destructor will be called when the number of references to any instance object drops to zero, but no explicit instance destructor has been called yet.

  • instanceFallbackDtorClosure -- [in] The closure passed to instanceFallbackDtorMostlyRequired. Use NO_CLOSURE if there is no instanceFallbackDtorMostlyRequired.

  • numComponents -- [in] The number of components in the components parameters

  • components -- [in] Zero or more components (interfaces, constructors, destructors and/or methods) of type struct dksdk_ffi_c_cls_generic_component.

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi or fullyQualifiedClassName is NULL.

  • DKSDK_FFI_ERR_INVALID_STATE when there is no more memory.

DKSDK_FFI_C_EXPORT struct dksdk_ffi_c_cls_generic_component dk_class_method(const char *name, DK_CLASS_METHOD *method, struct dksdk_ffi_c_cls_closure_data closure)

A class (also known as static) method.

Parameters:
  • name -- The name of the static method.

  • method -- The method call.

  • closure -- [in] The closure that will be passed in all subsequent method invocations.

Returns:

The struct dksdk_ffi_c_cls_generic_component you use in dk_add_class

DKSDK_FFI_C_EXPORT struct dksdk_ffi_c_cls_generic_component dk_class_destructor(const char *name, DK_CLASS_DESTRUCTOR *method, struct dksdk_ffi_c_cls_closure_data closure)

A class destructor.

Once a destructor is called, it is DkSDK FFI's responsibility to ensure no other destructor method will be called again for that class. In other words, the destructor is idempotent and will not create a double free bug. When a second destructor is called (or the same destructor is called twice), DkSDK FFI will ignore the second destructor call.

As a convenience to DkSDK FFI users, subsequent class methods may fail after a destructor has been called. However, because doing (atomic) checks for a prior destructor call on each class method call is expensive, release builds may have a relaxed memory consistency during the checks, or even optimize out the checks completely. It is the DkSDK FFI user's responsibility (you!) to not call more class methods after a destructor has been called.

Parameters:
  • name -- The name of the destructor method.

  • method -- The method call.

  • closure -- [in] The closure that will be passed in all subsequent method invocations.

Returns:

The struct dksdk_ffi_c_cls_generic_component you use in dk_add_class

DKSDK_FFI_C_EXPORT struct dksdk_ffi_c_cls_generic_component dk_instance_destructor(const char *name, DK_INSTANCE_DESTRUCTOR *method, struct dksdk_ffi_c_cls_closure_data closure)

An instance destructor.

Once a destructor is called, it is DkSDK FFI's responsibility to ensure no other destructor method will be called again for that instance. In other words, the destructor is idempotent and will not create a double free bug. When a second destructor is called (or the same destructor is called twice), DkSDK FFI will ignore the second destructor call.

As a convenience to DkSDK FFI users, subsequent instance methods may fail after a destructor has been called. However, because doing (atomic) checks for a prior destructor call on each instance method call is expensive, release builds may have a relaxed memory consistency during the checks, or even optimize out the checks completely. It is the DkSDK FFI user's responsibility (you!) to not call more instance methods after a destructor has been called.

Parameters:
  • name -- The name of the instance destructor.

  • method -- The method call.

  • closure -- [in] The closure that will be passed in all subsequent method invocations.

Returns:

The struct dksdk_ffi_c_cls_generic_component you use in dk_add_class

DKSDK_FFI_C_EXPORT struct dksdk_ffi_c_cls_generic_component dk_abstract_instance_destructor(const char *name)

An abstract instance destructor.

Once a destructor is called, it is DkSDK FFI's responsibility to ensure no other destructor method will be called again for that instance. In other words, the destructor is idempotent and will not create a double free bug. When a second destructor is called (or the same destructor is called twice), DkSDK FFI will ignore the second destructor call.

As a convenience to DkSDK FFI users, subsequent instance methods may fail after a destructor has been called. However, because doing (atomic) checks for a prior destructor call on each instance method call is expensive, release builds may have a relaxed memory consistency during the checks, or even optimize out the checks completely. It is the DkSDK FFI user's responsibility (you!) to not call more instance methods after a destructor has been called.

Parameters:

name -- The name of the instance destructor.

Returns:

The struct dksdk_ffi_c_cls_generic_component you use in dk_add_class

DKSDK_FFI_C_EXPORT struct dksdk_ffi_c_cls_generic_component dk_instance_method(const char *name, DK_INSTANCE_METHOD *method, struct dksdk_ffi_c_cls_closure_data closure)

An instance method.

Parameters:
  • name -- The name of the instance method.

  • method -- The method call.

  • closure -- [in] The closure that will be passed in all subsequent method invocations.

Returns:

The struct dksdk_ffi_c_cls_generic_component you use in dk_add_class

DKSDK_FFI_C_EXPORT struct dksdk_ffi_c_cls_generic_component dk_abstract_instance_method(const char *name)

An abstract instance method.

Parameters:

name -- The name of the abstract instance method.

Returns:

The struct dksdk_ffi_c_cls_generic_component you use in dk_add_class

DKSDK_FFI_C_EXPORT struct dksdk_ffi_c_cls_generic_component dk_interface(const char *name)

Add one of a maximum 63 interfaces that the class supports.

The interface name must have already been registered with a previous dk_add_class(ffi, INTERFACE_NAME), typically with all the methods as abstract methods.

Parameters:

name -- The fully qualified interface name.

Returns:

The struct dksdk_ffi_c_cls_generic_component you use in dk_add_class

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_cls_generic_new_instance(struct dksdk_ffi *ffi, struct dksdk_ffi_c_cls_generic_class_fields *ctor, const struct dksdk_ffi_c_cls_self_data self_data, dksdk_ffi_uuid *oid)

Create a new instance of a generic class from a given host object pointer.

Consider using dksdk_ffi_c_cls_generic_ref_to_new_object if you are implementing a DK_CLASS_METHOD class method.

Parameters:
  • ffi -- [in] The FFI pointer from dksdk_ffi_host_create.

  • ctor -- [in] A constructor value.

  • self_data -- [in] The representation of the self or this host object. May be zeroed for singleton or static host objects.

  • oid -- [out] Pointer to a UUID which will be populated with the new instance's object ID on success.

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi, genericClass or oid is NULL

  • DKSDK_FFI_ERR_INVALID_STATE when there is no memory to create a new instance, or the class constructor failed

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_cls_generic_ref_to_new_object(struct dksdk_ffi *ffi, const dksdk_ffi_uuid *iid, struct dksdk_ffi_c_cls_generic_class_fields *ctor, struct dksdk_ffi_c_cls_generic_call_ctx *ctx, const struct dksdk_ffi_c_cls_self_data self_data)

Convenience function to create an object, and then return an object reference to that object.

Typically used as the last statement in an implementation of a DK_CLASS_METHOD class method.

An object reference is a :Data blob with the first 128-bits as the object id, and the last 128-bits as the interface id. The return value will be populated with the object reference if successful.

Parameters:
  • ffi -- [in] The FFI pointer from dksdk_ffi_host_create.

  • iid -- [in] The pointer to the interface identifier (IID) that should be used when interacting with the object.

  • ctor -- [in] A constructor value, typically available as a parameter to a DK_CLASS_METHOD class method.

  • ctx -- [in] Context for the call.

  • self_data -- [in] The representation of the self or this host object. May be zeroed for singleton or static host objects.

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi, iid, ctor, or retval is NULL

  • DKSDK_FFI_ERR_INVALID_STATE when there is no memory to create a new instance, or the class constructor failed

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_cls_generic_delete_com_object(struct dksdk_ffi *ffi, struct ComObject com_object)

Deletes the specified COM object from the registry.

Typically used when inspecting the GenericReturn from a COM method call, and seeing a COM object reference when only a value was expected. You would need to delete the COM object reference and then return an error to your caller.

Parameters:
  • ffi -- [in] The FFI pointer from dksdk_ffi_host_create.

  • com_object -- [in] The 2 x 128-bit binary object reference to the COM object. The com_object Cap n' Proto structure's data pointer will be resolved with capn_resolve before it is read.

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when ffi is NULL or the com_f is not a valid COM object reference

  • DKSDK_FFI_ERR_NOT_FOUND when the object can't be found

static inline size_t zero_heap_size_estimator(const struct dksdk_ffi *ffi, const struct dksdk_ffi_c_cls_generic_instance *instance)

A heap size estimator that always returns zero.

Use when there is no heap space taken by an instance.

Variables

DKSDK_FFI_C_EXPORT const dksdk_ffi_uuid DK_IID_GENERIC_CLASS

The interface identifier for the class object dksdk_ffi_c_cls_generic.

DKSDK_FFI_C_EXPORT const struct dksdk_ffi_c_cls_closure_data NO_CLOSURE

A zeroed closure.

DKSDK_FFI_C_EXPORT struct dksdk_ffi_c_cls_generic_component DK_CLASS_END

The required end to the varargs list of components passed into dk_add_class.

struct capn_args_ret
#include <cls_generic.h>

Arguments and return value for a method call using Cap n' Proto messages.

Public Members

struct dk_cls_capnp_args *args

Arguments for a method call.

struct dk_cls_capnp_retval *retval

Return value from a method call.

struct dksdk_ffi_c_cls_closure_data
#include <cls_generic.h>

An opaque piece of data that captures the environment values that a method or destructor was defined in.

The closure data will be passed into the method or destructor on each method invocation or destructor call.

Public Members

char data[DK_CLS_MAX_FAT_POINTER_SZ]

A 256-bit opaque data blob that passed into an class/instance method or destructor.

The data is unique to the DkSDK FFI platform. For example, C does not have closures so this data will typically be zero (NO_CLOSURE) in C. Other platforms may use a pointer to their language's real closure, or "fat pointers" that are pointers annotated with extra data.

struct dksdk_ffi_c_cls_self_data
#include <cls_generic.h>

A representation of a self or this that will be passed into an instance method or instance destructor.

Public Members

char data[DK_CLS_MAX_FAT_POINTER_SZ]

The self or this as a fat pointer.

void *ptr

The self or this as a regular pointer.

Do not set directly. Instead use dksdk_ffi_c_cls_self_data_from_void_pointer so that the other bits are set to zero.

union dksdk_ffi_c_cls_self_data self

A pointer to the host object that FFI platforms pass as self or this into an instance method or instance destructor.

You have a choice of representing your host object pointer as a void * (ie. 64-bits on a 64-bit system) or a 256-bit opaque data. The 256-bit opaque data blob is the right choice on platforms that use "fat pointers" which are pointers annotated with extra data.

struct dksdk_ffi_c_cls_generic_call_ctx
#include <cls_generic.h>

The context of a call to a generic object.

Public Members

DK_MESSAGE_BUILDER *builder

Create a message that can be used to build a return value message from a method call, or an arguments message to a method call.

struct dk_cls_capnp_retval *return_value

The reference-counted return value message.

int host_configured_for_call_chain

Non-zero if and only if the host platform has been known to be configured for the call chain.

Being "configured" is platform specific, but generally includes setting up platform locks (if any) and/or platform thread local variables.

int guest_configured_for_call_chain

Non-zero if and only if the guest platform has been known to be configured for the call chain.

Being "configured" is platform specific, but generally includes setting up platform locks (if any) and/or platform thread local variables.

struct dksdk_ffi_c_cls_generic_instance
#include <cls_generic.h>

Values available to instance methods.

Public Members

struct dksdk_ffi_c_cls_self_data self_data

A representation of the host object that FFI platforms pass as self or this into an instance method or instance destructor.

struct dksdk_ffi_i_com *com

The COM object.

The COM object is useful to do dksdk_ffi_release(ffi, &instance->com) when an instance terminates itself.

struct dksdk_ffi_c_cls_generic_vtable
#include <cls_generic.h>

Virtual methods for the Generic class.

Public Members

dksdk_ffi_i_com_vtable com_vtable

The C++ style virtual table containing the Generic methods.

METHOD_DISPATCH *method_dispatch

The method dispatcher.

See METHOD_DISPATCH.

struct dksdk_ffi_c_cls_generic_instance_interface_fields
#include <cls_generic.h>

Values for an instance object, specific to a single one of its supported interfaces.

Public Members

dksdk_ffi_uuid interface_iid

One of the instance object's supported interfaces.

int is_concrete

Concrete (non-zero) means all interface methods are available as instance (not abstract) methods in the instance object.

struct dksdk_ffi_c_cls_generic_s128_set *method_names_opt

The names of the abstract and instance methods belonging to the supported interface.

NULL is valid if there are no methods.

struct dksdk_ffi_c_cls_generic_u32_set *abstract_instance_meth31_ids_opt

The abstract instance methods allowed by this interface.

The key is the meth31 method identifier.

struct dksdk_ffi_c_cls_generic_u32_set *abstract_instance_dtor31_ids_opt

The abstract destructor methods allowed by this interface.

The key is the meth31 method identifier.

struct dksdk_ffi_c_cls_generic_u32_set *instance_meth31_ids_opt

The instance methods allowed by this interface.

The key is the meth31 method identifier.

struct dksdk_ffi_c_cls_generic_u32_set *instance_dtor31_ids_opt

The destructors allowed by this interface.

The key is the meth31 method identifier.

enum dksdk_ffi_c_cls_generic_embedded_debug embedded_debug

Controls whether debug information embedded into the structure.

char truncated_interface_name[128]
struct dksdk_ffi_c_cls_generic_instance_fields
#include <cls_generic.h>

Values for an instance object.

Public Members

char self_data[DK_CLS_MAX_FAT_POINTER_SZ]

Pointer to the host object.

The pointer may be a "fat pointer" which is a regular pointer annotated with extra data.

DK_INSTANCE_DESTRUCTOR *fallback_instance_dtor2

Fallback destructor.

Required when there are explicit instance destructor methods. This destructor will be called for any instance which has had no explicit instance destructor call.

struct dksdk_ffi_c_cls_closure_data fallback_instance_dtor_closure2

Closure data for fallback_instance_dtor.

struct dksdk_ffi_c_cls_generic_slot
#include <cls_generic.h>

Values common to a slot (a constructor or a destructor or a method).

Public Members

DK_CLASS_METHOD *class_method
DK_CLASS_DESTRUCTOR *class_destructor
DK_INSTANCE_METHOD *instance_method
DK_INSTANCE_DESTRUCTOR *instance_destructor
union dksdk_ffi_c_cls_generic_slot slot
struct dksdk_ffi_c_cls_closure_data closure
int is_destructor
struct dksdk_ffi_c_cls_generic_class_fields
#include <cls_generic.h>

Values for a class object.

Public Members

dksdk_ffi_uuid clsid

CLSID.

int is_abstract

Abstract (non-zero) means that a new object can't be instantiated.

DK_CLASS_DESTRUCTOR *class_fallback_dtor_opt2

Fallback destructor.

Required when there are explicit class destructor methods. This destructor will be called for any class which has had no explicit class destructor call.

struct dksdk_ffi_c_cls_closure_data class_fallback_dtor_closure2

Closure data for class_fallback_dtor_opt.

DK_INSTANCE_HEAP_SIZE *new_instance_heap_size_over_estimator

The heap size, or an over-estimate of, instances.

size_t new_instance_num_slots

The number of slots new instance objects will support.

struct dksdk_ffi_c_cls_generic_slot *new_instance_slots

Array of instance functions.

The array is of length new_instance_num_slots

size_t new_instance_num_intfs

The number of interfaces new instance objects will support.

struct dksdk_ffi_c_cls_generic_instance_interface_fields *new_instance_interface_fields

Array of fields that will populate each interface of a new instance.

The array is of length new_instance_num_intfs

DK_INSTANCE_DESTRUCTOR *new_instance_fallback_dtor_opt2

Optional fallback destructor.

If specified, then this destructor will be called for any instance which has had no explicit destructor call.

struct dksdk_ffi_c_cls_closure_data new_instance_fallback_dtor_closure2

Closure passed to new_instance_fallback_dtor_opt.

struct dksdk_ffi_c_cls_generic_u32_u32_table *new_instance_method_dispatch_table

The method dispatch table for new instance objects.

struct dksdk_ffi_c_cls_generic
#include <cls_generic.h>

Generic is an object managed by the host language (C).

Its methods are dksdk_ffi_c_cls_generic_vtable.

Public Members

struct dksdk_ffi_i_com com

The always-valid DkSDK FFI COM superclass.

Use this superclass to access private fields of the DkSDK FFI COM superclass.

dksdk_ffi_c_cls_generic_vtable *vtable_generic

The always-valid virtual table for the Generic class.

Use this virtual table to access virtual methods.

union dksdk_ffi_c_cls_generic

The DkSDK FFI COM object superclass, with the virtual method table extended to conform to dksdk_ffi_c_cls_generic_vtable.

enum dksdk_ffi_c_cls_generic_object_type object_type

The type of generic_fields.

struct dksdk_ffi_c_cls_generic_u32_set *instance_dtor31_ids_opt

The instance destructors that are part of this interface.

The key is the meth31 method identifier.

Ignored and expected to be NULL if this is a class object.

struct dksdk_ffi_c_cls_generic_u32_set *instance_meth31_ids_opt

The instance methods that are part of this interface.

The key is the meth31 method identifier.

Ignored and expected to be NULL if this is a class object.

DK_INSTANCE_HEAP_SIZE *instance_heap_size_over_estimator

The heap size, or an over-estimate of, the instance object.

Ignored and expected to be NULL if this is a class object.

union dksdk_ffi_c_cls_generic::u_generic_fields generic_fields
enum dksdk_ffi_c_cls_generic_embedded_debug embedded_debug

Controls whether debug information embedded into the structure.

char truncated_interface_name[128]
union u_generic_fields
#include <cls_generic.h>

Either the class fields or the instance fields.

Public Members

struct dksdk_ffi_c_cls_generic_class_fields *class_fields_ptr

The class fields are pointers so there is only one source of truth.

Makes dealing with race conditions easier (only need to deal with thread synchronization).

struct dksdk_ffi_c_cls_generic_instance_fields *instance_fields_ptr

The instance fields are pointers so there is only one source of truth.

Makes dealing with race conditions easier (only need to deal with thread synchronization).

struct dksdk_ffi_c_cls_call_ctx_params
#include <cls_generic.h>

Parameters to dksdk_ffi_c_cls_call_ctx_nest.

Public Members

struct dksdk_ffi_c_cls_generic_call_ctx *callerPtr

The parent context.

struct dksdk_ffi_c_cls_generic_call_ctx *calleeAddr

The address of the will-be-initialized child struct dksdk_ffi_c_cls_generic_call_ctx.

On success, it will be initialized and will have its return_value message reference count set to 1.

struct dksdk_ffi_c_cls_generic_component
#include <cls_generic.h>

A component - the basic building block for a class - that is supplied to dk_add_class.

You do not create this structure directly. Instead use one of the following:

  • dk_abstract_instance_method

  • dk_abstract_instance_destructor

  • dk_class_method

  • dk_class_destructor

  • dk_instance_method

  • dk_instance_destructor

  • dk_interface

Public Members

enum dksdk_ffi_c_cls_generic_component_type component_type
char component_name[128]
char closure_data[DK_CLS_MAX_FAT_POINTER_SZ]
meth31 meth31
dksdk_ffi_uuid generic_interface_clsid
DK_CLASS_METHOD *class_method
DK_CLASS_DESTRUCTOR *class_destructor
DK_INSTANCE_METHOD *instance_method
DK_INSTANCE_DESTRUCTOR *instance_destructor