2.4 Defining Foreign Types
definition | ||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||
definition | ||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||
definition | ||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||
definition | ||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||
definition | ||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||
|
When id is provided by itself, then id represents an opaque type whose C representations is unspecified. An opaque type is useful only with the * type operator to create a pointer type that is tagged using the name id with a * suffix.
When id = parent_type is provided, then id is defined as an alias of parent_type. The tags as name of the type for pointer-tagging purposes remains the same as for parent_type.
When an options block is provided, then ~extends is required. If only ~extends is provided, then id represents an opaque type that creates a pointer subtype relative to parent_type: a pointer representing a value of id* has the tags of parent_type* with an additional tag at the end formed by tag_id suffixed with *. If tag_id is not specified with a ~tag option, then id is used for tag_id. The ~tag option is allowed only in this case.
When an options block has multiple options, then it defines a new type that has the same C-side representation as parent_type, but its Rhombus-side representation can be different as determined by other options as described below.
If foreign.type is followed by id(arg_id, ...), then id is defined as a type constructor that receives expression arguments when applied in a type position, and the remainder of the foreign.type form can refer to the arg_ids to parameterize the definition over supplied values. Each use of id must be applied to any many expression arguments as arg_ids in the definition.
In all cases, the new type id (or the type that it constructs) has the same C representation as parent_type. The Rhombus representation can be adjusted via ~rhombus_to_c and ~c_to_racket options, which may need accompanying ~predicate and ~release functions:
~predicate: Provides a predicate function as the result of the predicate_body sequence. This predicate is used when checks are enabled for Rhombus values to be converted to C for the type id, but the predicate can be skipped on request. The predicate determines whether a value is suitable as an argument to a function provided by ~rhombus_to_c. If predicate is not provided, then the predicate associated with parent_type is used.
~racket_to_c: Provides a conversion function toward C as the result of racket_to_c_body sequence. This converter is applied to a Rhombus value that is supplied for a id type. The result of conversion should be a Rhombus representation for parent_type. If ~racket_to_c is not provided, conversion is the identity function.
~release: Provides a function that finalizes conversion from Rhombus to C as the result of release_body sequence. The function is applied to the result of parent_type’s release function after the C value is delivered (e.g., passed in a foreign call that has returned). For base pointer types, the release function is Function.black_box, which is useful because it keeps a pointer live if it is subject to garbage collection. A release function could explicitly deallocate a pointer that was allocated by the ~racket_to_c function, but a release function is not called if control somehow escapes or the current thread is forcibly terminated.
~c_to_racket: Provides a conversion function toward Rhombus as the result of the c_to_racket_body sequence. This converter is applied to a Rhombus representation of parent_type as extracted from a C representation. The result of conversion should be a Rhombus representation for id. If ~c_to_racket is not provided, conversion is the identity function.
foreign.type percentage_t:
~extends: double_t
50.0
0.0025
foreign.type percentage_box_t:
~extends: ptr_t
~predicate: fun (bx): bx is_a Box && Box.value(bx) is_a percentage_t
p
~c_to_rhombus: fun (ptr):
Box(50.5)
0.505
foreign.type offset_double_t(delta):
~extends: double_t
foreign.struct posn_t (x :: offset_double_t(1.0),
y :: offset_double_t(2.0))
9.0
18.0
> p.x
100.0
99.0
definition | |
syntax class | |||||
| |||||
syntax class | |||||
| |||||
| |||||
syntax class | |||||
|
Like expr.Parsed, expr.AfterPrefixParsed, and expr.AfterInfixParsed, but for type positions.
4
foreign.struct Point_t(x :: int_t,
annotation | |
A type name typically doubles as an annotation itself, but foreign.type can be used with more complex type forms, such as ptr_t*.
#false
#true
definition | ||||||||
| ||||||||
| ||||||||
|
The numeric value of a id can be provided as a literal_int. If literal_int is not provided for an id, then the integer value is 0 if it is the first id, otherwise it is one more than the value for the preceding id.
When converting from C to Rhombus, if multiple ids have the same numeric value, the symbol form of the last listed id is used.
> foreign.enum shape_t int_t
| circle
| triangle = 3
| square
0
3
4
#'triangle
foreign type | ||||||||||||||||
| ||||||||||||||||
| ||||||||||||||||
| ||||||||||||||||
| ||||||||||||||||
|
Each of then_type amd else_type must be a scalar type, such as int_t or float_t. A system_case type is also scalar, since it selects among scalar types.