JlrsReflect.jl Documentation

One of the main features of jlrs is the possibility to easily convert data from Julia to Rust. By default only a few builtin types, like integers, arrays and modules are available, but this can be extended by using the JuliaStruct derive macro. One annoying aspect of this macro is that you need to figure out the correct layout first.

With JlrsReflect.jl you can automatically generate the appropriate bindings for many Julia types if you're using Julia 1.5. This includes types with unions, tuples, and type parameters. Even value types are not a problem because the bindings only contain type parameters that directly affect the layout. If a field contains pointers, featureful wrappers from jlrs with reasonable lifetimes are used. Two things that are not supported are structs with union or tuple fields that depend on a type parameter (eg struct SomeGenericStruct{T} a::Tuple{Int32, T} end, SomeGenericStruct{T} a::Union{Int32, T} end), and unions used as generic parameters (eg SomeGenericStruct{Union{A,B}}).

JlrsReflect.reflectFunction
reflect(types::Vector{<:Type})::Bindings

Generate Rust mappings for all types in types and their dependencies. The only requirement is that these types must not contain any union or tuple fields that depend on a free type parameter. Bindings are generated for the most general case by erasing the contents of all provided parameters, so you can't avoid this restriction by explicitly trying to avoid this restriction by providing a more qualified type. The only effect qualifying types has, is that bindings to these types will also be generated. The mappings will derive JuliaStruct, and IntoJulia if it's a bits type (with no free type parameters).

The result of this method can be written to a file, its contents will normally be a valid Rust module.

When you use these mappings with jlrs, these types must be available with the same path. For example, if you generate bindings for Main.Bar.Baz, this type must be available through that exact path and not some other path like Main.Foo.Bar.Baz.

Bits unions are turned into three fields for size and alignment requirement purposes. Besides a field with the same name that contains the raw data, a private field that enforces the proper alignment named _{fieldname}_align and a public field named {fieldname}_flag that contains the flag that indicates the active variant will be generated.

Example

julia> using JlrsReflect

julia> reflect([StackTraces.StackFrame])
#[repr(C)]
#[jlrs(julia_type = "Base.StackTraces.StackFrame")]
#[derive(Copy, Clone, Debug, JuliaStruct)]
pub struct StackFrame<'frame, 'data> {
    pub func: ::jlrs::value::symbol::Symbol<'frame>,
    pub file: ::jlrs::value::symbol::Symbol<'frame>,
    pub line: i64,
    pub linfo: ::jlrs::value::Value<'frame, 'data>,
    pub from_c: bool,
    pub inlined: bool,
    pub pointer: u64,
}

#[repr(C)]
#[jlrs(julia_type = "Core.CodeInfo")]
#[derive(Copy, Clone, Debug, JuliaStruct)]
pub struct CodeInfo<'frame, 'data> {
    pub code: ::jlrs::value::array::Array<'frame, 'data>,
    pub codelocs: ::jlrs::value::Value<'frame, 'data>,
    pub ssavaluetypes: ::jlrs::value::Value<'frame, 'data>,
    pub ssaflags: ::jlrs::value::array::Array<'frame, 'data>,
    pub method_for_inference_limit_heuristics: ::jlrs::value::Value<'frame, 'data>,
    pub linetable: ::jlrs::value::Value<'frame, 'data>,
    pub slotnames: ::jlrs::value::array::Array<'frame, 'data>,
    pub slotflags: ::jlrs::value::array::Array<'frame, 'data>,
    pub slottypes: ::jlrs::value::Value<'frame, 'data>,
    pub rettype: ::jlrs::value::Value<'frame, 'data>,
    pub parent: ::jlrs::value::Value<'frame, 'data>,
    pub edges: ::jlrs::value::Value<'frame, 'data>,
    pub min_world: u64,
    pub max_world: u64,
    pub inferred: bool,
    pub inlineable: bool,
    pub propagate_inbounds: bool,
    pub pure: bool,
}

#[repr(C)]
#[jlrs(julia_type = "Core.Nothing")]
#[derive(Copy, Clone, Debug, JuliaStruct)]
pub struct Nothing {
}
source
JlrsReflect.renamestruct!Function
renamestruct!(bindings::Bindings, type::Type, rename::String)

Change a struct's name. This can be useful if the name of a struct results in invalid Rust code or causes warnings.

Example

julia> using JlrsReflect

julia> struct Foo end;

julia> bindings = reflect([Foo]);

julia> renamestruct!(bindings, Foo, "Bar")

julia> bindings
#[repr(C)]
#[jlrs(julia_type = "Main.Foo")]
#[derive(Copy, Clone, Debug, JuliaStruct)]
pub struct Bar {
}
source
JlrsReflect.renamefields!Function
renamefields!(bindings::Bindings, type::Type, rename::Dict{Symbol,String})
renamefields!(bindings::Bindings, type::Type, rename::Vector{Pair{Symbol,String})

Change some field names of a struct. This can be useful if the name of a struct results in invalid Rust code or causes warnings.

Example

julia> using JlrsReflect

julia> struct Food
    🍔::Bool
end;

julia> bindings = reflect([Food]);

julia> renamefields!(bindings, Food, [:🍔 => "burger"])

julia> bindings
#[repr(C)]
#[jlrs(julia_type = "Main.Foo")]
#[derive(Copy, Clone, Debug, JuliaStruct)]
pub struct Food {
    burger: bool
}
source