This project offers cool ways to interact between these super safe & supe fast languages!
Rust <===> C# interop at the highest level!
This effect is created by using special libraries on the C# side and on the Rust side.
The library provides a mini interface for the Rust library to interact with the DotNet environment.
private struct BridgeConvention
{
public delegate* <object, Type> FGetType;
public delegate* <string, bool, Type> FSearchType;
public delegate* <Type, int, void*> FGetMethodAtSlot;
public delegate* <Type, object> FAlloc;
public delegate* <byte*, int, string> FAllocString;
public delegate* <Type, int, Array> FAllocArray;
public delegate* <delegate*<void>, Exception> FTryCatch;
public delegate* <Exception, void> FThrow;
}
The developer must connect the library to the interface using a function call:
RustishkaBridge.Bridge.ConnectRustModule(string libPath, out IntPtr moduleHandle) // to load lib and connect
// or
RustishkaBridge.Bridge.ConnectRustModule(IntPtr moduleHandle) // connect without loading. Use if the module has already been loaded before.
The developer provides an export function with this signature. It will be called in ConnectRustModule
initialize_rustishka!();
Structures with class content for Rust have to be created manually.
You can use Sharplab as well.
- Rust lib can search for a type in the DotNet runtime:
let integer_type = search_type_cached(&String::from("System.Int32"), false);
- Rust lib can allocate objects & arrays:
let someType = search_type_cached(&someTypeAQN, false);
let obj: *mut NetObject<SomeType> = allocate(someType); // alloc without constructor invoke !!!
- Rust lib can call virtual functions:
let someType: *mut NetObject<SystemType> = ...;
let baseType = someType.get_base_type();
This is presented in the form of pseudo wrappers:
define_virtual!(pub, get_base_type, 11, 4, *mut NetObject<SystemType>);
where: 11 - row eq slotId / 8
, 4 - index eq slotId % 8
- Rust lib can call non-virtual instance and static functions.
someObject.some_instance_method(args);
NetObject::<SomeObject>::some_static_method(args)
let val: *mut NetObject<SomeObject> = SomeObject::new(args);
where
impl NetObject<SomeObject> {
define_function!(pub some_instance_method, 7, self: *mut Self, arg_name: ArgType); // where 7 - slotId
define_function!(pub some_static_method, 8, arg_name: ArgType);
}
impl SomeObject {
define_constructor!(pub new, arg_name: ArgType);
}
- Rust lib can access to static fields
SomeObject::get_cool_static_field();
// where
define_typeof!(SomeObject, "blahblah");
impl SomeObject {
define_static_field!(pub get_cool_static_field, "CoolStaticField", SomeFieldType);
}
- Rust lib can use typeof sugar
pub struct SomeObject { }
define_typeof!(SomeObject, "SomeObject AssemblyQualifiedName");
// in method
let ty : *mut NetObject<SystemType> = SomeObject::type_of();
- Rust lib can easily alloc managed arrays
managed_array!(ElementType, elements num, elements);
// ex:
managed_array!(i32, 5, 0, 1, 2, 3, 4);
managed_array!(SystemType, 2, i32::type_of(), f32::type_of());
- Rust lib can use almost all of .NET Reflection's features! (Even use DynamicMethod!)
As you can see: it`s very human design, very easy to use.
- Add support for field access
- .Net type inheritance in Rust by creating a custom type via .Net TypeBuilder & overriding methodtable entries.
- Source generators (atm it's scary Rustishka.Tools)