Code Monkey home page Code Monkey logo

ffidji's Introduction

FFIDJI

FFIDJI is a Foreign Function Interface code generator.
You can use it to automatically generate bindings for simple to complex types and delegates between different languages, like calling Rust or C native code from C# for instance.

crustsharp

(It actually works the same way with several different languages, checkout documentation to see what's supported)

Supported Languages

  • C# to RUST
  • C# to C/C++

Many more to come!

Benchmark

'''

Method Mean Error StdDev Ratio RatioSD Gen 0 Gen 1 Allocated
Concat Managed 13.90 ns 0.361 ns 0.822 ns 1.00 0.00 0.0076 - 48 B
Concat FFIDJI 303.69 ns 6.162 ns 10.296 ns 21.87 1.44 0.0076 - 48 B
Concat Protobuf Grpc 217,729.81 ns 4,329.875 ns 7,807.658 ns 15,756.08 1,126.16 1.4648 0.4883 9,795 B
'''

Example

Interface

<Interface name="SampleInterface">
    <!--define your custom types-->
    <Type name="PairToSum">
        <Field name="a" type="int32"/>
        <Field name="b" type="int32"/>
    </Type>
    <Type name="ArrayToSum">
        <Field name="intsToSum" type="int32" array="true"/>
    </Type>
    <!--define your methods-->
    <Method name="Sum">
        <Parameter name="A" type="int32"/>
        <Parameter name="B" type="int32"/>
        <Return name="C" type="int32"/>
    </Method>
    <Method name="SumPair">
        <Parameter name="input" type="PairToSum"/>
        <Return name="sum" type="int32"/>
    </Method>
    <Method name="SumArray">
        <Parameter name="input" type="ArrayToSum"/>
        <Return name="sum" type="int32"/>
    </Method>
</Interface>

Command

ffidji -f csharp MyCsharpProject/MyGeneratedInterface.cs -t c MyCppProject/MyHeader.h -i MyInterface.xml

Generated output

C#

// Autogenerated by FFIDJI

using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

using int8 = System.SByte;
using uint8 = System.Byte;
using int16 = System.Int16;
using uint16 = System.UInt16;
using int32 = System.Int32;
using uint32 = System.UInt32;
using int64 = System.Int64;
using uint64 = System.UInt64;
using float16 = System.Half;
using float32 = System.Single;
using float64 = System.Double;

namespace FFIDJI
{
    public static class SampleInterface
    {
        public const string LIBRARY_NAME = "MyNativeLibrary.dll";

        private readonly struct Arr<T>
        {
            public readonly IntPtr ptr;
            public readonly int size;
            public Arr(IntPtr ptr, int size)
            {
                this.ptr = ptr;
                this.size = size;
            }
        }

        private unsafe static T[] CopyArray<T>(IntPtr ptr, int size) where T : unmanaged
        {
            int length = size * Marshal.SizeOf<T>();
            T[] array = new T[size];
            void* u_src = ptr.ToPointer();
            fixed (T* u_dst = &array[0])
            {
                Unsafe.CopyBlock(u_dst, u_src, (uint)length);
            }
            return array;
        }

        private static T[] Convert<T>(Arr<T> arr) where T : unmanaged
        {
            return CopyArray<T>(arr.ptr, arr.size);
        }

        private static T Convert<T>(T obj) where T : unmanaged
        {
            return obj;
        }

        private unsafe static Arr<T> Convert<T>(T[] array) where T : unmanaged
        {
            int length = array.Length * sizeof(T);
            IntPtr ptr = Alloc(length);
            void* u_dst = ptr.ToPointer();
            fixed (T* u_src = &array[0])
            {
                Unsafe.CopyBlock(u_dst, u_src, (uint)length);
            }
            return new Arr<T>(ptr, array.Length);
        }

        [DllImport(LIBRARY_NAME, EntryPoint = "Free_FFI")]
        private static extern void Free(IntPtr ptr);

        [DllImport(LIBRARY_NAME, EntryPoint = "Alloc_FFI")]
        private static extern IntPtr Alloc(int length);

        [StructLayout(LayoutKind.Sequential)]
        public struct PairToSum
        {
            public int32 a;
            public int32 b;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct ArrayToSum
        {
            public int32[] intsToSum;
        }

        private static unsafe void Free(ArrayToSum_FFI input)
        {
            Free(input.intsToSum.ptr);
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct ArrayToSum_FFI
        {
            public Arr<int32> intsToSum;
        }

        private static ArrayToSum Convert(ArrayToSum_FFI data_FFI)
        {
            return new ArrayToSum
            {
                intsToSum = Convert(data_FFI.intsToSum),
            };
        }

        private static ArrayToSum_FFI Convert(ArrayToSum data)
        {
            return new ArrayToSum_FFI
            {
                intsToSum = Convert(data.intsToSum),
            };
        }

        private unsafe static ArrayToSum[] Convert(Arr<ArrayToSum_FFI> arr)
        {
            var array_ffi = CopyArray<ArrayToSum_FFI>(arr.ptr, arr.size);
            var array = new ArrayToSum[arr.size];
            for (int i = 0; i < arr.size; ++i) array[i] = Convert(array_ffi[i]);
            return array;
        }

        [DllImport(LIBRARY_NAME, EntryPoint = "Sum")]
        private extern static int32 Sum_FFI(int32 A, int32 B);

        public static int32 Sum(int32 A, int32 B)
        {
            var A_ffi = Convert(A);
            var B_ffi = Convert(B);
            var result_ffi = Sum_FFI(A_ffi, B_ffi);
            var result = Convert(result_ffi);
            return result;
        }

        [DllImport(LIBRARY_NAME, EntryPoint = "SumPair")]
        private extern static int32 SumPair_FFI(PairToSum input);

        public static int32 SumPair(PairToSum input)
        {
            var input_ffi = Convert(input);
            var result_ffi = SumPair_FFI(input_ffi);
            var result = Convert(result_ffi);
            return result;
        }

        [DllImport(LIBRARY_NAME, EntryPoint = "SumArray")]
        private extern static int32 SumArray_FFI(ArrayToSum_FFI input);

        public static int32 SumArray(ArrayToSum input)
        {
            var input_ffi = Convert(input);
            var result_ffi = SumArray_FFI(input_ffi);
            Free(input_ffi);
            var result = Convert(result_ffi);
            return result;
        }
    }
}

C/C++

You only need to implement generated interface!

// Autogenerated by FFIDJI

#include <stdint.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C"
{
#endif

typedef int8_t int8;
typedef uint8_t uint8;
typedef int16_t int16;
typedef uint16_t uint16;
typedef int32_t int32;
typedef uint32_t uint32;
typedef long int64;
typedef unsigned long uint64;
typedef float float32;
typedef double float64;

__declspec(dllexport) inline void* Alloc_FFI(int32 length)
{
    return (void*)malloc(length);
}

__declspec(dllexport) inline void Free_FFI(void* ptr)
{
    free(ptr);
}

struct PairToSum
{
    int32 a;
    int32 b;
};

struct ArrayToSum
{
    int32* intsToSum_ptr;
    int intsToSum_len;
};

__declspec(dllexport) int32 Sum(int32 A, int32 B);

__declspec(dllexport) int32 SumPair(PairToSum input);

__declspec(dllexport) int32 SumArray(ArrayToSum input);

#ifdef __cplusplus
}
#endif

Links

See The Rust FFI Omnibus for more info on how to marshal to rust

ffidji's People

Contributors

ogxd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

ffidji's Issues

Prevent duplicated names

Prevent duplicated type names, method names or argument names within a single method definition

Do a performance benchmark

This will require some setup. Ideally, it could be a rust example (see Cargo).
When done, publish results in the documentation.

What benchmark?
There is actually nothing that really compares to ffidji, so the idea would be to create a C#/rust app that really benefits from using native code.

Create docs CI

Add CI on master push to autogenerate and publish documentation on github pages

Add unit/integration tests

FFIDJI is not an easy tool to unit test however there are still some things that can be made. The effort is worth especially at this early stage.
Also, setup the CI to run the tests.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.