ore

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 15, 2024 License: MIT Imports: 9 Imported by: 0

README

ore - Generic Dependency Injection Container for Go

Go Report Card Go Reference Mentioned in Awesome Go Maintainability codecov

ore


ore is a lightweight, generic & simple dependency injection (DI) container for Go.

Inspired by the principles of ASP.NET Dependency Injection, designed to facilitate the management of object lifetimes and the inversion of control in your applications.


Features

  • Singletons: Register components as singletons, ensuring that there's only one instance throughout the entire application.

  • Transients: Register components as transients, creating a new instance each time it is requested.

  • Scoped Instances: Register components as scoped, tying them to a specific context or scope. Scoped components are created once per scope and reused within that scope.

  • Lazy Initialization: Support for lazy initialization of components, allowing for efficient resource utilization.

  • Multiple Implementations of the Same Interface: Register and retrieve several implementations of the same interface type, allowing for flexible and modular design.

  • Keyed Services Injection: Support for injecting services based on a key, allowing you to differentiate between multiple implementations of the same interface or type.

  • Concurrency-Safe: Utilizes a mutex to ensure safe concurrent access to the container.


Installation

go get -u github.com/firasdarwish/ore

Usage

Import
import "github.com/firasdarwish/ore"
Example Service
// interface
type Counter interface {
  AddOne()
  GetCount() int
}

// implementation
type simpleCounter struct {
  counter int
}

func (c *simpleCounter) AddOne()  {
  c.counter++
}

func (c *simpleCounter) GetCount() int {
  return c.counter
}

func (c *simpleCounter) New(ctx context.Context) Counter {
  return &simpleCounter{}
}

Eager Singleton
package main

import (
  "context"
  "github.com/firasdarwish/ore"
)

func main() {
  var c Counter
  c = &simpleCounter{}

  // register
  ore.RegisterEagerSingleton[Counter](c)

  ctx := context.Background()

  // retrieve
  c, ctx := ore.Get[Counter](ctx)
  c.AddOne()
  c.AddOne()
}

Lazy (using Creator[T] interface)
package main

import (
  "context"
  "fmt"
  "github.com/firasdarwish/ore"
)

func main() {
  // register
  ore.RegisterLazyCreator[Counter](ore.Scoped, &simpleCounter{})

  // OR
  //ore.RegisterLazyCreator[Counter](ore.Transient, &simpleCounter{})
  //ore.RegisterLazyCreator[Counter](ore.Singleton, &simpleCounter{})

  ctx := context.Background()

  // retrieve
  c, ctx := ore.Get[Counter](ctx)
  c.AddOne()
  c.AddOne()

  // retrieve again
  c, ctx = ore.Get[Counter](ctx)
  c.AddOne()

  // prints out: `TOTAL: 3`
  fmt.Println("TOTAL: ", c.GetCount())
}

Lazy (using anonymous func)
package main

import (
  "context"
  "fmt"
  "github.com/firasdarwish/ore"
)

func main() {
  // register
  ore.RegisterLazyFunc[Counter](ore.Scoped, func(ctx context.Context) Counter {
    return &simpleCounter{}
  })

  // OR
  //ore.RegisterLazyFunc[Counter](ore.Transient, func(ctx context.Context) Counter {
  //  return &simpleCounter{}
  //})

  // Keyed service registration
  //ore.RegisterLazyFunc[Counter](ore.Singleton, func(ctx context.Context) Counter {
  // return &simpleCounter{}
  //}, "name here", 1234)

  ctx := context.Background()

  // retrieve
  c, ctx := ore.Get[Counter](ctx)
  c.AddOne()
  c.AddOne()

  // Keyed service retrieval
  //c, ctx := ore.Get[Counter](ctx, "name here", 1234)

  // retrieve again
  c, ctx = ore.Get[Counter](ctx)
  c.AddOne()

  // prints out: `TOTAL: 3`
  fmt.Println("TOTAL: ", c.GetCount())
}

Several Implementations
package main

import (
  "context"
  "github.com/firasdarwish/ore"
)

func main() {
  // register
  ore.RegisterLazyCreator[Counter](ore.Scoped, &simpleCounter{})

  ore.RegisterLazyCreator[Counter](ore.Scoped, &yetAnotherCounter{})

  ore.RegisterLazyFunc[Counter](ore.Transient, func(ctx context.Context) Counter {
    return &simpleCounter{}
  })

  ore.RegisterLazyCreator[Counter](ore.Singleton, &yetAnotherCounter{})

  ctx := context.Background()

  // returns a slice of `Counter` implementations
  counters, ctx := ore.GetList[Counter](ctx)

  // to retrieve a slice of keyed services
  //counters, ctx := ore.GetList[Counter](ctx, "my integer counters")

  for _, c := range counters {
    c.AddOne()
  }

  // It will always return the LAST registered implementation
  defaultImplementation, ctx := ore.Get[Counter](ctx) // simpleCounter
  defaultImplementation.AddOne()
}


Keyed Services Retrieval Example
package main

import (
  "context"
  "fmt"
  "github.com/firasdarwish/ore"
)

func main() {
  // register
  ore.RegisterLazyFunc[Counter](ore.Singleton, func(ctx context.Context) Counter {
    return &simpleCounter{}
  }, "name here", 1234)

  //ore.RegisterLazyCreator[Counter](ore.Scoped, &simpleCounter{}, "name here", 1234)

  //ore.RegisterEagerSingleton[Counter](&simpleCounter{}, "name here", 1234)

  ctx := context.Background()

  // Keyed service retrieval
  c, ctx := ore.Get[Counter](ctx, "name here", 1234)
  c.AddOne()

  // prints out: `TOTAL: 1`
  fmt.Println("TOTAL: ", c.GetCount())
}

More Complex Example


type Numeric interface {
	int
}

type GenericCounter[T Numeric] interface {
  Add(number T)
  GetCount() T
}

type genericCounter[T Numeric] struct {
  counter T
}

func (gc *genericCounter[T]) Add(number T) {
  gc.counter += number
}

func (gc *genericCounter[T]) GetCount(ctx context.Context) T {
  return gc.counter
}
package main

import (
  "context"
  "github.com/firasdarwish/ore"
)

func main() {

  // register
  ore.RegisterLazyFunc[GenericCounter[int]](ore.Scoped, func(ctx context.Context) GenericCounter[int] {
    return &genericCounter[int]{}
  })

  // retrieve
  c, ctx := ore.Get[GenericCounter[int]](ctx)
}


Benchmarks

goos: windows
goarch: amd64
pkg: github.com/firasdarwish/ore
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
BenchmarkRegisterLazyFunc
BenchmarkRegisterLazyFunc-20             5404572               209.6 ns/op
BenchmarkRegisterLazyCreator
BenchmarkRegisterLazyCreator-20          5683119               195.5 ns/op
BenchmarkRegisterEagerSingleton
BenchmarkRegisterEagerSingleton-20       5335443               218.8 ns/op
BenchmarkGet
BenchmarkGet-20                          4231207               279.8 ns/op
BenchmarkGetList
BenchmarkGetList-20                      2098818               544.6 ns/op

Contributing

Feel free to contribute by opening issues, suggesting features, or submitting pull requests. We welcome your feedback and contributions.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Index

Constants

View Source
const (
	Singleton Lifetime = "singleton"
	Transient          = "transient"
	Scoped             = "scoped"
)

Variables

This section is empty.

Functions

func Build

func Build()

func Get

func Get[T any](ctx context.Context, key ...KeyStringer) (T, context.Context)

Get Retrieves an instance based on type and key (panics if no valid implementations)

func GetList

func GetList[T any](ctx context.Context, key ...KeyStringer) ([]T, context.Context)

GetList Retrieves a list of instances based on type and key

func RegisterEagerSingleton

func RegisterEagerSingleton[T comparable](impl T, key ...KeyStringer)

RegisterEagerSingleton Registers an eagerly instantiated singleton value

func RegisterLazyCreator

func RegisterLazyCreator[T any](lifetime Lifetime, creator Creator[T], key ...KeyStringer)

RegisterLazyCreator Registers a lazily initialized value using a `Creator[T]` interface

func RegisterLazyFunc

func RegisterLazyFunc[T any](lifetime Lifetime, initializer Initializer[T], key ...KeyStringer)

RegisterLazyFunc Registers a lazily initialized value using an `Initializer[T]` function signature

Types

type Counter

type Counter interface {
	AddOne()
	GetCount() int
}

type CounterGeneric

type CounterGeneric[T numeric] interface {
	Add(number T)
	GetCount() T
}

type CounterWriter

type CounterWriter interface {
	Add(number int)
	GetCount() int
}

type Creator

type Creator[T any] interface {
	New(ctx context.Context) T
}

type Initializer

type Initializer[T any] func(ctx context.Context) T

type KeyStringer

type KeyStringer any

type Lifetime added in v0.1.1

type Lifetime string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL