{"id":16081786,"url":"https://github.com/ginger-code/fsharp.extensions.dependencyinjection","last_synced_at":"2025-04-05T11:41:44.413Z","repository":{"id":180316901,"uuid":"664938551","full_name":"ginger-code/FSharp.Extensions.DependencyInjection","owner":"ginger-code","description":"Demonstration of F# integration with .NET DI to allow for typed function injection without extra performance overhead","archived":false,"fork":false,"pushed_at":"2023-07-17T03:58:38.000Z","size":103,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-10T22:44:05.621Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"F#","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/ginger-code.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-11T04:58:10.000Z","updated_at":"2023-07-12T02:55:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"2b4b6350-6102-4578-a4cd-024ce5eb4421","html_url":"https://github.com/ginger-code/FSharp.Extensions.DependencyInjection","commit_stats":{"total_commits":21,"total_committers":2,"mean_commits":10.5,"dds":0.04761904761904767,"last_synced_commit":"d6cc12042a9eb11f0e342d551c872daac230623a"},"previous_names":["ginger-code/fsharp.extensions.dependencyinjection"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ginger-code%2FFSharp.Extensions.DependencyInjection","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ginger-code%2FFSharp.Extensions.DependencyInjection/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ginger-code%2FFSharp.Extensions.DependencyInjection/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ginger-code%2FFSharp.Extensions.DependencyInjection/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ginger-code","download_url":"https://codeload.github.com/ginger-code/FSharp.Extensions.DependencyInjection/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247332522,"owners_count":20921852,"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","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":[],"created_at":"2024-10-09T11:10:00.094Z","updated_at":"2025-04-05T11:41:44.389Z","avatar_url":"https://github.com/ginger-code.png","language":"F#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FSharp.Extensions.DependencyInjection\n\nThis project is a POC to demonstrate a method of creating typed wrappers for functions and injecting them automatically into an `IServiceCollection` using reflection and marker attributes _without incurring a performance penalty or using any interfaces_.\n\nThis works because functions wrapped in single-case struct unions are optimized to into raw function pointers by the compiler- this offers practically equivalent performance as simply calling a function directly! A breakdown of benchmarks supporting this claim are included, below.\n\nUsing this strategy, developers can achieve things like obtaining function definitions directly from the `HttpContext` within an `HttpHandler` when using `Giraffe`; these injected functions can be composed before injection, meaning it's completely compatible with functional dependency injection both before injection and after retrieval! \n\n## Getting started\n\nDefine the wrapper type and implementation in your library code:\n```fsharp\nopen FSharp.Extensions.DependencyInjection\n\n/// Define a wrapper struct DU with one case containing a function type\n[\u003cStruct\u003e]\ntype AddOne = AddOne of (int -\u003e int)\n\nmodule Wrappers =\n    /// Create an instance of the wrapper containing an implementation of the function\n    [\u003cInjectedFunction\u003e]\n    let addOne = (+) 1 |\u003e AddOne\n\n```\n\nAutomatically inject the functions from your startup code:\n\n```fsharp\nopen FSharp.Extensions.DependencyInjection\n\ntype Startup() =\n    member _.ConfigureServices(services: IServiceCollection) =\n        services.AddAllInjectedFunctions() // or services.AddAllInjectedFunctionsParallel()\n\n// ... etc.\n```\n\nRetrieve and reference the function in your `HttpHandler` code:\n\n```fsharp\nlet addOne (i: int) : HttpHandler =\n    fun next ctx -\u003e\n        let (AddOne addOne) = ctx.GetService()\n        let result = addOne i\n        text $\"{i} + 1 = {result}\" next ctx\n```\n\n\n\n## Performance Considerations\n\n### General Function Call Overhead\n\n| Method | Mean | Error | StdDev | Code Size | Gen0 | Allocated |\n| --- | --- | --- | --- | --- | --- | --- |\n| RawFunctionPointer | 4.046 ns | 0.0163 ns | 0.0136 ns | 1,094 B | - | - |\n| StructDUWrappedFunctionPointer | 4.050 ns | 0.0310 ns | 0.0275 ns | 1,094 B | - | - |\n| ClassDUWrappedFunctionPointer | 6.488 ns | 0.0669 ns | 0.0522 ns | 1,126 B | 0.0019 | 24 B |\n\n### Generated Assembly for Function Calls\n\n```assembly\n; Benchmarks.FunctionPointerBenchmarks+FunctionPointerBenchmarks.RawFunctionPointer()\n       7FF9CFDF4120 push      rsi\n       7FF9CFDF4121 sub       rsp,20\n       7FF9CFDF4125 mov       rcx,7FF9D01EDE50\n       7FF9CFDF412F mov       edx,5\n       7FF9CFDF4134 call      CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE\n       7FF9CFDF4139 mov       rcx,1D3B0406BA8\n       7FF9CFDF4143 mov       rsi,[rcx]\n       7FF9CFDF4146 mov       rcx,7FF9D00648B0\n       7FF9CFDF4150 mov       edx,5\n       7FF9CFDF4155 call      CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE\n       7FF9CFDF415A mov       edx,[7FF9D00648EC]\n       7FF9CFDF4160 mov       r8d,[7FF9D00648E8]\n       7FF9CFDF4167 mov       rcx,rsi\n       7FF9CFDF416A add       rsp,20\n       7FF9CFDF416E pop       rsi\n       7FF9CFDF416F jmp       qword ptr [7FF9D0201678]; Microsoft.FSharp.Core.FSharpFunc`2[[System.Int32, System.Private.CoreLib],[System.Int32, System.Private.CoreLib]].InvokeFast[[System.Int32, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2\u003cInt32,Microsoft.FSharp.Core.FSharpFunc`2\u003cInt32,Int32\u003e\u003e, Int32, Int32)\n; Total bytes of code 85\n```\n\n```assembly\n; Benchmarks.FunctionPointerBenchmarks+FunctionPointerBenchmarks.StructDUWrappedFunctionPointer()\n       7FF9CFDF4120 push      rsi\n       7FF9CFDF4121 sub       rsp,20\n;         Add.instance |\u003e fun (Add add) -\u003e add a b\n;         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n       7FF9CFDF4125 mov       rcx,7FF9D01EDE50\n       7FF9CFDF412F mov       edx,5\n       7FF9CFDF4134 call      CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE\n       7FF9CFDF4139 mov       rcx,276C3C06BA8\n       7FF9CFDF4143 mov       rsi,[rcx]\n       7FF9CFDF4146 mov       rcx,7FF9D00648B0\n       7FF9CFDF4150 mov       edx,5\n       7FF9CFDF4155 call      CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE\n       7FF9CFDF415A mov       edx,[7FF9D00648EC]\n       7FF9CFDF4160 mov       r8d,[7FF9D00648E8]\n       7FF9CFDF4167 mov       rcx,rsi\n       7FF9CFDF416A add       rsp,20\n       7FF9CFDF416E pop       rsi\n       7FF9CFDF416F jmp       qword ptr [7FF9D0201738]; Microsoft.FSharp.Core.FSharpFunc`2[[System.Int32, System.Private.CoreLib],[System.Int32, System.Private.CoreLib]].InvokeFast[[System.Int32, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2\u003cInt32,Microsoft.FSharp.Core.FSharpFunc`2\u003cInt32,Int32\u003e\u003e, Int32, Int32)\n; Total bytes of code 85\n```\n\n```assembly\n; Benchmarks.FunctionPointerBenchmarks+FunctionPointerBenchmarks.ClassDUWrappedFunctionPointer()\n       7FF9CFDE4120 push      rdi\n       7FF9CFDE4121 push      rsi\n       7FF9CFDE4122 sub       rsp,28\n;         Add2.instance |\u003e fun (Add2 add) -\u003e add a b\n;         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n       7FF9CFDE4126 mov       rcx,7FF9D01DDE50\n       7FF9CFDE4130 mov       edx,5\n       7FF9CFDE4135 call      CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE\n       7FF9CFDE413A mov       rcx,23DD6406BA8\n       7FF9CFDE4144 mov       rsi,[rcx]\n       7FF9CFDE4147 mov       rdi,rsi\n       7FF9CFDE414A mov       rcx,offset MT_Library.StructFunctions+Add2\n       7FF9CFDE4154 call      CORINFO_HELP_NEWSFAST\n       7FF9CFDE4159 lea       rcx,[rax+8]\n       7FF9CFDE415D mov       rdx,rdi\n       7FF9CFDE4160 call      CORINFO_HELP_ASSIGN_REF\n       7FF9CFDE4165 mov       rcx,7FF9D00548B0\n       7FF9CFDE416F mov       edx,5\n       7FF9CFDE4174 call      CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE\n       7FF9CFDE4179 mov       edx,[7FF9D00548EC]\n       7FF9CFDE417F mov       r8d,[7FF9D00548E8]\n       7FF9CFDE4186 mov       rcx,rsi\n       7FF9CFDE4189 add       rsp,28\n       7FF9CFDE418D pop       rsi\n       7FF9CFDE418E pop       rdi\n       7FF9CFDE418F jmp       qword ptr [7FF9D01F1720]; Microsoft.FSharp.Core.FSharpFunc`2[[System.Int32, System.Private.CoreLib],[System.Int32, System.Private.CoreLib]].InvokeFast[[System.Int32, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2\u003cInt32,Microsoft.FSharp.Core.FSharpFunc`2\u003cInt32,Int32\u003e\u003e, Int32, Int32)\n; Total bytes of code 117\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fginger-code%2Ffsharp.extensions.dependencyinjection","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fginger-code%2Ffsharp.extensions.dependencyinjection","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fginger-code%2Ffsharp.extensions.dependencyinjection/lists"}