# Rustishka 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. # Overview #### C# Side The library provides a mini interface for the Rust library to interact with the DotNet environment. ```csharp private struct BridgeConvention { public delegate* FGetType; public delegate* FSearchType; public delegate* FGetMethodAtSlot; public delegate* FAlloc; public delegate* FAllocString; public delegate* FAllocArray; public delegate* , Exception> FTryCatch; public delegate* FThrow; } ``` The developer must connect the library to the interface using a function call: ```csharp 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. ``` #### Rust side The developer provides an export function with this signature. It will be called in ConnectRustModule ```Rust initialize_rustishka!(); ``` #### Important thing Structures with class content for Rust have to be created manually. [A tool for obtaining offsets](https://github.com/SergeyTeplyakov/ObjectLayoutInspector) You can use Sharplab as well. # Features - Rust lib can search for a type in the DotNet runtime: ```rust let integer_type = search_type_cached(&String::from("System.Int32"), false); ``` - Rust lib can allocate objects & arrays: ```rust let someType = search_type_cached(&someTypeAQN, false); let obj: *mut NetObject = allocate(someType); // alloc without constructor invoke !!! ``` - Rust lib can call virtual functions: ```rust let someType: *mut NetObject = ...; let baseType = someType.get_base_type(); ``` This is presented in the form of pseudo wrappers: ```rust define_virtual!(pub, get_base_type, 11, 4, *mut NetObject); ``` where: 11 - row eq `slotId / 8`, 4 - index eq `slotId % 8` - Rust lib can call non-virtual instance and static functions. ```rust someObject.some_instance_method(args); NetObject::::some_static_method(args) let val: *mut NetObject = SomeObject::new(args); ``` where ```rust impl NetObject { 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 ```Rust 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 ```Rust pub struct SomeObject { } define_typeof!(SomeObject, "SomeObject AssemblyQualifiedName"); // in method let ty : *mut NetObject = SomeObject::type_of(); ``` - Rust lib can easily alloc managed arrays ```Rust 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. # Examples [C# side](https://github.com/badryuner/rustishka/blob/master/Rustishka.Tests/SomeTests.cs) [Rust side](https://github.com/badryuner/rustishka/blob/master/rustishka_examples/src/lib.rs) # TODO - 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)