[][src]Trait jlrs::traits::JuliaStruct

pub unsafe trait JuliaStruct: Copy { }

This trait can be derived in order to provide a mapping between a type in Julia and one in Rust. When this trait is derived, the following traits are implemented:

With these traits implemented you can use Value::cast with this custom type.

Rather than manually implement the appropriate structs, you should use JlrsReflect.jl to generate them for you. If you do choose to implement this trait manually, the following rules apply.

First, the struct must be annotated with #[repr(C)] to ensure the compiler won't change the layout. Second, the struct must be annotated with #[jlrs(julia_type = "Path.To.Type")] where the path provides the full name of the type, eg the path for a struct namedBar in the module Foo which is a submodule of Main is Main.Foo.Bar. When this type is used, it must be available at that location. This path must not contain any type parameters.

Struct have fields and these fields have types. The type can belong to one of the following classes:

  • DataType
  • UnionAll
  • Union
  • TypeVar

If the field type is a DataType the field will either be allocated inline or stored as a Value. If it's allocated inline, a valid binding for that field must be used. In some cases, for example a field that contains a Module, that type can be used as a specialized type. Many of the types defined in the submodules of value can be used this way.

Special care must be taken if the field type is a tuple type. Unlike other types, tuples are covariant in the parameters. This means that a tuple like Tuple{Int32, Int64} is a subtype of Tuple{Int32, Real}. As a result, a tuple type can only be instantiated if all of its fields are concrete types. If the field type is a concrete tuple type, it is stored inline and can be represented by the appropriate type from the tuple module, otherwise it will not be stored inline and a Value must be used instead.

UnionAlls are straightforward, they're never allocated inline and must always be mapped to a Value.

Similar to tuples, unions can have two representation depending on the type parameters. If all types are pointer-free, the bits union optimization will apply. Otherwise it is stored as a Value.

The bits union optimization is not straightforward to map to Rust. In fact, three fields are required. Unlike normal structs the size of a bits union field doesn't have to be an integer multiple of its alignment; it will have the alignment of the variant with the largest alignment and is as large as the largest possible variant. Additionally, there will be another u8 that is used as a flag to indicate the active variant.

The first field is the correct zero-sized Align#-type defined in the union module. The second a BitsUnion from that same module, its type parameter must be an array of MaybeUninit<u8>s with the appropriate numbber of elements. Finally, a u8 must be used as a flag. In order for the derive macro to handle these fields correctly, they must be annotated with #[jlrs(bits_union_align)], #[jlrs(bits_union)], and #[jlrs(bits_union_flag)] respectively.

Finally, a TypeVar field will be mapped to a type parameter in Rust. A parameter that doesn't affect the layout must be elided. The type parameter must implement both ValidLayout and Copy.

Implementors

Loading content...