{"id":14992022,"url":"https://github.com/ogxd/ffidji","last_synced_at":"2026-01-20T21:02:45.625Z","repository":{"id":45605868,"uuid":"404113015","full_name":"ogxd/ffidji","owner":"ogxd","description":"🐶 FFIDJI is a tool to automatically generate bindings between languages, like calling Rust code from C# for instance.","archived":false,"fork":false,"pushed_at":"2022-07-19T21:43:57.000Z","size":3227,"stargazers_count":8,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-16T12:53:55.181Z","etag":null,"topics":["cplusplus","csharp","dotnet","ffi","ffi-bindings","interop","interoperability","pinvoke","rust","rust-lang"],"latest_commit_sha":null,"homepage":"https://ogxd.github.io/ffidji","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ogxd.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-09-07T20:23:45.000Z","updated_at":"2023-10-30T23:00:53.000Z","dependencies_parsed_at":"2022-09-02T18:42:32.604Z","dependency_job_id":null,"html_url":"https://github.com/ogxd/ffidji","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ogxd/ffidji","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ogxd%2Fffidji","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ogxd%2Fffidji/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ogxd%2Fffidji/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ogxd%2Fffidji/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ogxd","download_url":"https://codeload.github.com/ogxd/ffidji/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ogxd%2Fffidji/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276932065,"owners_count":25730715,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-25T02:00:09.612Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cplusplus","csharp","dotnet","ffi","ffi-bindings","interop","interoperability","pinvoke","rust","rust-lang"],"created_at":"2024-09-24T15:00:39.434Z","updated_at":"2025-09-25T14:30:40.959Z","avatar_url":"https://github.com/ogxd.png","language":"Rust","funding_links":[],"categories":["FFI Bindings"],"sub_categories":[],"readme":"# FFIDJI\n\nFFIDJI is a Foreign Function Interface code generator.  \nYou 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.\n\n![crustsharp](https://raw.githubusercontent.com/ogxd/ffidji/master/docs/static/images/ppap.png)\n\n_(It actually works the same way with several different languages, checkout [documentation](https://ogxd.github.io/ffidji/) to see what's supported)_\n\n## Supported Languages\n\n- C# to RUST\n- C# to C/C++\n\n_Many more to come!_\n\n## [Full Documentation](https://ogxd.github.io/ffidji/)\n\n## Benchmark\n\n'''\n|               Method |          Mean |        Error |       StdDev |     Ratio |  RatioSD |  Gen 0 |  Gen 1 | Allocated |\n|--------------------- |--------------:|-------------:|-------------:|----------:|---------:|-------:|-------:|----------:|\n|       Concat Managed |      13.90 ns |     0.361 ns |     0.822 ns |      1.00 |     0.00 | 0.0076 |      - |      48 B |\n|        Concat FFIDJI |     303.69 ns |     6.162 ns |    10.296 ns |     21.87 |     1.44 | 0.0076 |      - |      48 B |\n| 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 |\n'''\n\n## Example\n\n### Interface\n\n```xml\n\u003cInterface name=\"SampleInterface\"\u003e\n    \u003c!--define your custom types--\u003e\n    \u003cType name=\"PairToSum\"\u003e\n        \u003cField name=\"a\" type=\"int32\"/\u003e\n        \u003cField name=\"b\" type=\"int32\"/\u003e\n    \u003c/Type\u003e\n    \u003cType name=\"ArrayToSum\"\u003e\n        \u003cField name=\"intsToSum\" type=\"int32\" array=\"true\"/\u003e\n    \u003c/Type\u003e\n    \u003c!--define your methods--\u003e\n    \u003cMethod name=\"Sum\"\u003e\n        \u003cParameter name=\"A\" type=\"int32\"/\u003e\n        \u003cParameter name=\"B\" type=\"int32\"/\u003e\n        \u003cReturn name=\"C\" type=\"int32\"/\u003e\n    \u003c/Method\u003e\n    \u003cMethod name=\"SumPair\"\u003e\n        \u003cParameter name=\"input\" type=\"PairToSum\"/\u003e\n        \u003cReturn name=\"sum\" type=\"int32\"/\u003e\n    \u003c/Method\u003e\n    \u003cMethod name=\"SumArray\"\u003e\n        \u003cParameter name=\"input\" type=\"ArrayToSum\"/\u003e\n        \u003cReturn name=\"sum\" type=\"int32\"/\u003e\n    \u003c/Method\u003e\n\u003c/Interface\u003e\n```\n\n### Command\n\n`ffidji -f csharp MyCsharpProject/MyGeneratedInterface.cs -t c MyCppProject/MyHeader.h -i MyInterface.xml`\n\n### Generated output\n\n#### C#\n\n```csharp\n// Autogenerated by FFIDJI\n\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Runtime.CompilerServices;\n\nusing int8 = System.SByte;\nusing uint8 = System.Byte;\nusing int16 = System.Int16;\nusing uint16 = System.UInt16;\nusing int32 = System.Int32;\nusing uint32 = System.UInt32;\nusing int64 = System.Int64;\nusing uint64 = System.UInt64;\nusing float16 = System.Half;\nusing float32 = System.Single;\nusing float64 = System.Double;\n\nnamespace FFIDJI\n{\n    public static class SampleInterface\n    {\n        public const string LIBRARY_NAME = \"MyNativeLibrary.dll\";\n\n        private readonly struct Arr\u003cT\u003e\n        {\n            public readonly IntPtr ptr;\n            public readonly int size;\n            public Arr(IntPtr ptr, int size)\n            {\n                this.ptr = ptr;\n                this.size = size;\n            }\n        }\n\n        private unsafe static T[] CopyArray\u003cT\u003e(IntPtr ptr, int size) where T : unmanaged\n        {\n            int length = size * Marshal.SizeOf\u003cT\u003e();\n            T[] array = new T[size];\n            void* u_src = ptr.ToPointer();\n            fixed (T* u_dst = \u0026array[0])\n            {\n                Unsafe.CopyBlock(u_dst, u_src, (uint)length);\n            }\n            return array;\n        }\n\n        private static T[] Convert\u003cT\u003e(Arr\u003cT\u003e arr) where T : unmanaged\n        {\n            return CopyArray\u003cT\u003e(arr.ptr, arr.size);\n        }\n\n        private static T Convert\u003cT\u003e(T obj) where T : unmanaged\n        {\n            return obj;\n        }\n\n        private unsafe static Arr\u003cT\u003e Convert\u003cT\u003e(T[] array) where T : unmanaged\n        {\n            int length = array.Length * sizeof(T);\n            IntPtr ptr = Alloc(length);\n            void* u_dst = ptr.ToPointer();\n            fixed (T* u_src = \u0026array[0])\n            {\n                Unsafe.CopyBlock(u_dst, u_src, (uint)length);\n            }\n            return new Arr\u003cT\u003e(ptr, array.Length);\n        }\n\n        [DllImport(LIBRARY_NAME, EntryPoint = \"Free_FFI\")]\n        private static extern void Free(IntPtr ptr);\n\n        [DllImport(LIBRARY_NAME, EntryPoint = \"Alloc_FFI\")]\n        private static extern IntPtr Alloc(int length);\n\n        [StructLayout(LayoutKind.Sequential)]\n        public struct PairToSum\n        {\n            public int32 a;\n            public int32 b;\n        }\n\n        [StructLayout(LayoutKind.Sequential)]\n        public struct ArrayToSum\n        {\n            public int32[] intsToSum;\n        }\n\n        private static unsafe void Free(ArrayToSum_FFI input)\n        {\n            Free(input.intsToSum.ptr);\n        }\n\n        [StructLayout(LayoutKind.Sequential)]\n        private struct ArrayToSum_FFI\n        {\n            public Arr\u003cint32\u003e intsToSum;\n        }\n\n        private static ArrayToSum Convert(ArrayToSum_FFI data_FFI)\n        {\n            return new ArrayToSum\n            {\n                intsToSum = Convert(data_FFI.intsToSum),\n            };\n        }\n\n        private static ArrayToSum_FFI Convert(ArrayToSum data)\n        {\n            return new ArrayToSum_FFI\n            {\n                intsToSum = Convert(data.intsToSum),\n            };\n        }\n\n        private unsafe static ArrayToSum[] Convert(Arr\u003cArrayToSum_FFI\u003e arr)\n        {\n            var array_ffi = CopyArray\u003cArrayToSum_FFI\u003e(arr.ptr, arr.size);\n            var array = new ArrayToSum[arr.size];\n            for (int i = 0; i \u003c arr.size; ++i) array[i] = Convert(array_ffi[i]);\n            return array;\n        }\n\n        [DllImport(LIBRARY_NAME, EntryPoint = \"Sum\")]\n        private extern static int32 Sum_FFI(int32 A, int32 B);\n\n        public static int32 Sum(int32 A, int32 B)\n        {\n            var A_ffi = Convert(A);\n            var B_ffi = Convert(B);\n            var result_ffi = Sum_FFI(A_ffi, B_ffi);\n            var result = Convert(result_ffi);\n            return result;\n        }\n\n        [DllImport(LIBRARY_NAME, EntryPoint = \"SumPair\")]\n        private extern static int32 SumPair_FFI(PairToSum input);\n\n        public static int32 SumPair(PairToSum input)\n        {\n            var input_ffi = Convert(input);\n            var result_ffi = SumPair_FFI(input_ffi);\n            var result = Convert(result_ffi);\n            return result;\n        }\n\n        [DllImport(LIBRARY_NAME, EntryPoint = \"SumArray\")]\n        private extern static int32 SumArray_FFI(ArrayToSum_FFI input);\n\n        public static int32 SumArray(ArrayToSum input)\n        {\n            var input_ffi = Convert(input);\n            var result_ffi = SumArray_FFI(input_ffi);\n            Free(input_ffi);\n            var result = Convert(result_ffi);\n            return result;\n        }\n    }\n}\n```\n\n#### C/C++\n\nYou only need to implement generated interface!\n\n```c++\n// Autogenerated by FFIDJI\n\n#include \u003cstdint.h\u003e\n#include \u003cstdlib.h\u003e\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\ntypedef int8_t int8;\ntypedef uint8_t uint8;\ntypedef int16_t int16;\ntypedef uint16_t uint16;\ntypedef int32_t int32;\ntypedef uint32_t uint32;\ntypedef long int64;\ntypedef unsigned long uint64;\ntypedef float float32;\ntypedef double float64;\n\n__declspec(dllexport) inline void* Alloc_FFI(int32 length)\n{\n    return (void*)malloc(length);\n}\n\n__declspec(dllexport) inline void Free_FFI(void* ptr)\n{\n    free(ptr);\n}\n\nstruct PairToSum\n{\n    int32 a;\n    int32 b;\n};\n\nstruct ArrayToSum\n{\n    int32* intsToSum_ptr;\n    int intsToSum_len;\n};\n\n__declspec(dllexport) int32 Sum(int32 A, int32 B);\n\n__declspec(dllexport) int32 SumPair(PairToSum input);\n\n__declspec(dllexport) int32 SumArray(ArrayToSum input);\n\n#ifdef __cplusplus\n}\n#endif\n```\n\n## Links\n\nSee [The Rust FFI Omnibus](http://jakegoulding.com/rust-ffi-omnibus/string_arguments/) for more info on how to marshal to rust","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fogxd%2Fffidji","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fogxd%2Fffidji","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fogxd%2Fffidji/lists"}