Skip to content

Repository files navigation

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.

privatestructBridgeConvention{publicdelegate*<object,Type>FGetType;publicdelegate*<string,bool,Type>FSearchType;publicdelegate*<Type,int,void*>FGetMethodAtSlot;publicdelegate*<Type,object>FAlloc;publicdelegate*<byte*,int,string>FAllocString;publicdelegate*<Type,int,Array>FAllocArray;publicdelegate*<delegate*<void>,Exception>FTryCatch;publicdelegate*<Exception,void>FThrow;}

The developer must connect the library to the interface using a function call:

RustishkaBridge.Bridge.ConnectRustModule(stringlibPath,outIntPtrmoduleHandle)// to load lib and connect// or
RustishkaBridge.Bridge.ConnectRustModule(IntPtrmoduleHandle)// 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

initialize_rustishka!();

Important thing

Structures with class content for Rust have to be created manually.

A tool for obtaining offsets

You can use Sharplab as well.

Features

  • 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:*mutNetObject<SomeType> = allocate(someType);// alloc without constructor invoke !!!
  • Rust lib can call virtual functions:
let someType:*mutNetObject<SystemType> = ...;let baseType = someType.get_base_type();

This is presented in the form of pseudo wrappers:

define_virtual!(pub, get_base_type,11,4,*mutNetObject<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:*mutNetObject<SomeObject> = SomeObject::new(args);

where

implNetObject<SomeObject>{define_function!(pub some_instance_method,7,self:*mutSelf, arg_name:ArgType);// where 7 - slotIddefine_function!(pub some_static_method,8, arg_name:ArgType);}implSomeObject{define_constructor!(pub new, arg_name:ArgType);}
  • Rust lib can access to static fields
SomeObject::get_cool_static_field();// wheredefine_typeof!(SomeObject,"blahblah");implSomeObject{define_static_field!(pub get_cool_static_field,"CoolStaticField",SomeFieldType);}
  • Rust lib can use typeof sugar
pubstructSomeObject{}define_typeof!(SomeObject,"SomeObject AssemblyQualifiedName");// in methodlet ty :*mutNetObject<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.

Examples

C# side

Rust side

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)

About

Rust + C# = 💘

Topics

Resources

Stars

9 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages