Crates.io | rustishka |
lib.rs | rustishka |
version | 0.1.1 |
source | src |
created_at | 2024-05-20 12:15:55.794163 |
updated_at | 2024-10-15 12:17:15.685381 |
description | Better Interop between C# and Rust |
homepage | |
repository | https://github.com/BadRyuner/rustishka |
max_upload_size | |
id | 1245668 |
size | 197,719 |
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.
let integer_type = search_type_cached(&String::from("System.Int32"), false);
let someType = search_type_cached(&someTypeAQN, false);
let obj: *mut NetObject<SomeType> = allocate(someType); // alloc without constructor invoke !!!
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
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);
}
SomeObject::get_cool_static_field();
// where
define_typeof!(SomeObject, "blahblah");
impl SomeObject {
define_static_field!(pub get_cool_static_field, "CoolStaticField", SomeFieldType);
}
pub struct SomeObject { }
define_typeof!(SomeObject, "SomeObject AssemblyQualifiedName");
// in method
let ty : *mut NetObject<SystemType> = SomeObject::type_of();
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());
As you can see: it`s very human design, very easy to use.