Generating bindings
We can generate bindings for Julia types with the reflect
function found in the Reflect
module of JlrsCore.jl, it can be called with a vector of types.
julia> using JlrsCore.Reflect
julia> struct MyStruct
a::Int8
b::Tuple{Int8, UInt8}
end
julia> struct MyWrapper
ms::MyStruct
end
julia> reflect([MyWrapper])
#[repr(C)]
#[derive(Clone, Debug, Unbox, ValidLayout, Typecheck, IntoJulia, ValidField, IsBits, ConstructType, CCallArg, CCallReturn)]
#[jlrs(julia_type = "Main.MyStruct")]
pub struct MyStruct {
pub a: i8,
pub b: ::jlrs::data::layout::tuple::Tuple2<i8, u8>,
}
#[repr(C)]
#[derive(Clone, Debug, Unbox, ValidLayout, Typecheck, IntoJulia, ValidField, IsBits, ConstructType, CCallArg, CCallReturn)]
#[jlrs(julia_type = "Main.MyWrapper")]
pub struct MyWrapper {
pub ms: MyStruct,
}
As we can see, only MyWrapper
has to be included to recursively generate bindings for MyStruct
as well.1 The generated bindings derive all traits they can, and are annotated with the path to the type they've been generated from. It's important that this path matches the path where the type exists at runtime.
reflect
has two keyword parameters, f16
and complex
. Either of these can be set to true when the feature with the same name is enabled for jlrs to map a Float16
to half::f16
and Complex{T}
to num::Complex<T>
respectively.
There are three things that reflect
can't handle:
- Types that have a field with a
Union
type that references a generic parameter. - Types that have a field with a
Tuple
type that references a generic parameter. - Types with atomic fields.2
Note that this list doesn't include Union
fields in general; as long as all possible variants are known, the layout is static and a valid layout can be generated:
julia> using JlrsCore.Reflect
julia> struct MyBitsUnionStruct
u::Union{Int16, Tuple{UInt8, UInt8, UInt8, UInt8, UInt8}}
end
julia> struct MyUnionStruct
u::Union{Int16, Vector{UInt8}}
end
julia> reflect([MyBitsUnionStruct, MyUnionStruct])
#[repr(C)]
#[derive(Clone, Debug, Unbox, ValidLayout, Typecheck, ValidField, ConstructType, CCallArg)]
#[jlrs(julia_type = "Main.MyBitsUnionStruct")]
pub struct MyBitsUnionStruct {
#[jlrs(bits_union_align)]
_u_align: ::jlrs::data::layout::union::Align2,
#[jlrs(bits_union)]
pub u: ::jlrs::data::layout::union::BitsUnion<5>,
#[jlrs(bits_union_flag)]
pub u_flag: u8,
}
#[repr(C)]
#[derive(Clone, Debug, Unbox, ValidLayout, Typecheck, ValidField, ConstructType, CCallArg)]
#[jlrs(julia_type = "Main.MyUnionStruct")]
pub struct MyUnionStruct<'scope, 'data> {
pub u: ::std::option::Option<::jlrs::data::managed::value::ValueRef<'scope, 'data>>,
}
Support for inlined unions is limited to representation, the BitsUnion
type is an opaque blob of bytes.
If bindings for a parametric type are requested, the most generic bindings are generated:
julia> using JlrsCore.Reflect
julia> struct MyParametricStruct{T}
a::T
end
julia> reflect([MyParametricStruct{UInt8}])
#[repr(C)]
#[derive(Clone, Debug, Unbox, ValidLayout, Typecheck, ValidField, IsBits, ConstructType, CCallArg, CCallReturn)]
#[jlrs(julia_type = "Main.MyParametricStruct")]
pub struct MyParametricStruct<T> {
pub a: T,
}
Despite asking for bindings for MyParametricStruct{UInt8}
, we got them for MyParametricStruct{T}
.
Any type parameter that doesn't affect the layout is elided. In this case a separate layout type and type constructor are generated, which are linked with the HasLayout
trait:
julia> using JlrsCore.Reflect
julia> struct MyElidedStruct{T}
a::UInt8
end
julia> reflect([MyElidedStruct{UInt8}])
#[repr(C)]
#[derive(Clone, Debug, Unbox, ValidLayout, Typecheck, ValidField, IsBits)]
#[jlrs(julia_type = "Main.MyElidedStruct")]
pub struct MyElidedStruct {
pub a: u8,
}
#[derive(ConstructType, HasLayout)]
#[jlrs(julia_type = "Main.MyElidedStruct", constructor_for = "MyElidedStruct", scope_lifetime = false, data_lifetime = false, layout_params = [], elided_params = ["T"], all_params = ["T"])]
pub struct MyElidedStructTypeConstructor<T> {
_t: ::std::marker::PhantomData<T>,
}
Every type that is recursively inlined into the requested layout is included.
Type constuctors are generated for types with atomic fields.