2.6 Foreign Functions
foreign type | ||||||||||||||||||||
| ||||||||||||||||||||
foreign type | ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
|
When a function type is used to convert a C function pointer to Rhombus, then calling the Rhombus function is a foreign callout. When a function type is use to convert a Rhombus function to a C function pointer, then it represents a foreign callback.
The args_tuple component of a function type describes the argument types for a C procedure. The tuple can be a single type, or it can be a parenthesized sequence of argument descriptions. If ~varargs appears in the argument sequence, it corresponds to a point in the argument sequence where the remainder is represented by just ... in a C function prototype; the Racket representation of the function expects additional arguments described after ~varargs as required arguments (so, a C function that has variable arguments must be converted through a different type for each different combination of arguments to be supplied).
Each argument is represented by an arg_type, an optional arg_id, and an optional auto_expr. If an argument has an arg_id, it can be referenced by later auto_exprs as well as in result_tuple and a body sequence. If an argument has a auto_expr, then auto_expr supplies the Rhombus representation of an argument to be passed to a C function for a foreign callout, while the Rhombus representation of a callout omits the argument; an auto_expr is not used for a foreign callback.
The result_tuple component describes the result protocol for the C function. It has at least a result_type, and it may have an errno. The C representation of the result_type describes the result from the C function. If an errno is present, then the Rhombus representation for a foreign callout returns two values (when no body sequence is present): a converted value for the C result and an integer for the value of the C library’s errno or Windows’s GetLastError() just after the C function returns. The C function result can have a result_id, and an errno result can have an optional errno_id; those identifiers can be referenced in a body sequence. An errno component is not used for a foreign callback.
If a non-empty body sequence is present, then it determines the result of the Rhombus representation of the function for a foreign callout. A body sequence can refer to the original arguments and the results via arg_ids, result_id, and/or errno_id. A body sequence is not used for a foreign callback.
Additional arrow_options affects the way a C function is called or how a callback is handled:
~abi abi: Uses abi as the ABI for a foreign callout or foreign callback. See default_abi, cdecl_abi, and stdcall_abi.
~atomic: Adjusts a foreign callout to potentially improve performance. The foreign function must not invoke any callbacks or otherwise reach the Rhombus run-time system, so it can be considered an atomic operation from the perspective of Rhombus. This option has no effect on foreign callbacks.
~collect_safe: Adjusts a foreign callout to allow Rhombus garbage collection concurrent with the call, or adjusts a foreign callback to re-enable synchronization with the garbage collector during the callback (i.e., only collect-safe callbacks are allowed to be invoked via a collect-safe procedure call; a collect-safe callback can be invoked through a non-collect-safe foreign procedure call). Note that a collect-safe call makes sense only when arguments to the foreign procedure are not managed by the Rhombus garbage collector or are immobile and reliably retained.
~allow_callback_exn: Adjusts a foreign callout so that a foreign callback is allowed to raise an exception that escape the foreign-function call. This option has no effect on foreign callbacks themselves. A foreign callback must never raise an exception unless it is invoked via foreign function call using this option.
~in_original: Adjusts a foreign callout to take place in a coroutine thread within Rhombus’s main place (which is useful if the foreign function is not thread-safe), or adjusts a foreign callback invocation so that it takes place in a coroutine thread within the current place (which can be useful if the callback might otherwise run in a thread not created by Rhombus). The callout or callback happens in the context of an unspecified Rhombus coroutine thread, so it must not raise an exception.
> strlen_ptr
#<ptr_t>
5
definition | ||||||||||||||||||||
| ||||||||||||||||||||
definition | ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
| ||||||||||||||||||||
|
When a result_annot is present, it provides an annotation for the result of the Racket function defined as id. The result value is checked against the annotation when :: is used (as opposed to :~).
When ~fail is provided, then fail_handler_expr should produce a function that expects one argument. When a relevant export is not found in the result of lib_expr, then the result of fail_handler_expr is called with the name that was not found (i.e., c_id or id).
When ~wrap is provided, then wrapper_expr should produce a function that expects one argument. In that case, the value that id would be bound to is passed to the result of wrapper_expr, and id is defined as the result of the wrapper.
foreign.fun strlen(string_t) :: int_t:
~lib: Lib.load(#false) // => C library
> strlen("hello")
5
foreign.fun verbose_strlen(s :: string_t) :: (len :: int_t) :: String:
~lib: Lib.load(#false) // => C library
~c_id: strlen
@str{The string @repr(s) has @len bytes in its UTF-8 encoding}
> println(verbose_strlen("π day"))
The string "π day" has 6 bytes in its UTF-8 encoding
definition | ||||||||||||
| ||||||||||||
definition | ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
|
If & appears before id, then id is defined as a pointer object with static information to indicate type as the content type.
If & does not appear before id, then id is defined as a the conversion of the content at a C library export (which is an address) to the Rhombus representation of type.
definition | ||||||||||||
| ||||||||||||
| ||||||||||||
|
If ~default_fail is specified, then the result of fail_handler_expr is used for a ~fail clause if a use of id.def or id.fun does not include one.
If ~default_wrap is specified, then the result of wrapper_expr is used for a ~wrap clause if a use of id.fun does not include one.
foreign ABI | |||
| |||
foreign ABI | |||
| |||
foreign ABI | |||
| |||
foreign ABI | |||
|
The system_case ABI form is analogous to system_case for types.