Skip to content

Commit

Permalink
Pre release/code documentation (#29)
Browse files Browse the repository at this point in the history
* Adds documentation comments to the pkg/types package
* Adds documentation comments to the pkg/resolving package
* Adds documentation comments to the pkg/registration package
  • Loading branch information
matzefriedrich authored Sep 19, 2024
1 parent d03ab91 commit 5aca612
Show file tree
Hide file tree
Showing 19 changed files with 217 additions and 15 deletions.
4 changes: 4 additions & 0 deletions pkg/registration/activator.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"reflect"
)

// CreateServiceActivatorFrom creates a service activator function for a given instance of type T.
func CreateServiceActivatorFrom[T any](instance T) (func() T, error) {
if internal.IsNil(instance) {
return nil, types.NewRegistryError(types.ErrorInstanceCannotBeNil)
Expand All @@ -25,6 +26,9 @@ func CreateServiceActivatorFrom[T any](instance T) (func() T, error) {
return instanceFunc, nil
}

// RegisterInstance registers an instance of type T. A registered instance behaves like a service registration with
// a singleton lifetime scope. See https://matzefriedrich.github.io/parsley-docs/registration/register-instances/ for
// further information.
func RegisterInstance[T any](registry types.ServiceRegistry, instance T) error {
instanceFunc, err := CreateServiceActivatorFrom[T](instance)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/registration/dependency.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type dependencyInfo struct {

var _ types.DependencyInfo = &dependencyInfo{}

// NewDependencyInfo creates a new instance of types.DependencyInfo with the provided service registration, instance, and parent dependency.
func NewDependencyInfo(registration types.ServiceRegistration, instance interface{}, consumer types.DependencyInfo) types.DependencyInfo {
return &dependencyInfo{
registration: registration,
Expand Down
2 changes: 2 additions & 0 deletions pkg/registration/named_service_registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"github.com/matzefriedrich/parsley/pkg/types"
)

// NamedServiceRegistrationFunc defines a function that returns a service name, its activator function, and its lifetime scope. This type supports the internal infrastructure.
type NamedServiceRegistrationFunc func() (name string, activatorFunc any, scope types.LifetimeScope)

// NamedServiceRegistration registers a service with a specified name, activator function, and lifetime scope.
func NamedServiceRegistration(name string, activatorFunc any, scope types.LifetimeScope) NamedServiceRegistrationFunc {
return func() (string, any, types.LifetimeScope) {
return name, activatorFunc, scope
Expand Down
10 changes: 10 additions & 0 deletions pkg/registration/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ type serviceRegistry struct {
registrations map[types.ServiceKey]types.ServiceRegistrationList
}

// RegisterTransient adds a transient service registration with the provided activator function.
// See https://matzefriedrich.github.io/parsley-docs/registration/register-constructor-functions/ for further information.
func RegisterTransient(registry types.ServiceRegistry, activatorFunc any) error {
return registry.Register(activatorFunc, types.LifetimeTransient)
}

// RegisterScoped adds a scoped service registration with the provided activator function.
func RegisterScoped(registry types.ServiceRegistry, activatorFunc any) error {
return registry.Register(activatorFunc, types.LifetimeScoped)
}

// RegisterSingleton adds a singleton service registration with the provided activator function.
func RegisterSingleton(registry types.ServiceRegistry, activatorFunc any) error {
return registry.Register(activatorFunc, types.LifetimeSingleton)
}
Expand All @@ -32,6 +36,7 @@ func (s *serviceRegistry) addOrUpdateServiceRegistrationListFor(serviceType type
return list
}

// Register adds a service registration with the provided activator function and lifetime scope.
func (s *serviceRegistry) Register(activatorFunc any, lifetimeScope types.LifetimeScope) error {

registration, err := CreateServiceRegistration(activatorFunc, lifetimeScope)
Expand All @@ -49,6 +54,7 @@ func (s *serviceRegistry) Register(activatorFunc any, lifetimeScope types.Lifeti
return nil
}

// RegisterModule registers one or more modules with the service registry.
func (s *serviceRegistry) RegisterModule(modules ...types.ModuleFunc) error {
for _, m := range modules {
err := m(s)
Expand All @@ -59,11 +65,13 @@ func (s *serviceRegistry) RegisterModule(modules ...types.ModuleFunc) error {
return nil
}

// IsRegistered checks if a service type is registered in the service registry.
func (s *serviceRegistry) IsRegistered(serviceType types.ServiceType) bool {
_, found := s.registrations[serviceType.LookupKey()]
return found
}

// TryGetServiceRegistrations Tries to find all available service registrations for the given service type.
func (s *serviceRegistry) TryGetServiceRegistrations(serviceType types.ServiceType) (types.ServiceRegistrationList, bool) {
if s.IsRegistered(serviceType) == false {
return nil, false
Expand All @@ -75,6 +83,7 @@ func (s *serviceRegistry) TryGetServiceRegistrations(serviceType types.ServiceTy
return nil, false
}

// TryGetSingleServiceRegistration Tries to find a single service registration for the given service type.
func (s *serviceRegistry) TryGetSingleServiceRegistration(serviceType types.ServiceType) (types.ServiceRegistration, bool) {
list, found := s.TryGetServiceRegistrations(serviceType)
if found && list.IsEmpty() == false {
Expand All @@ -87,6 +96,7 @@ func (s *serviceRegistry) TryGetSingleServiceRegistration(serviceType types.Serv
return nil, false
}

// NewServiceRegistry creates a new types.ServiceRegistry instance.
func NewServiceRegistry() types.ServiceRegistry {
registrations := make(map[types.ServiceKey]types.ServiceRegistrationList)
return &serviceRegistry{
Expand Down
3 changes: 3 additions & 0 deletions pkg/registration/registry_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type multiRegistryAccessor struct {
registries []types.ServiceRegistryAccessor
}

// TryGetSingleServiceRegistration attempts to find a single service registration for the given service type in multiple registries.
func (m *multiRegistryAccessor) TryGetSingleServiceRegistration(serviceType types.ServiceType) (types.ServiceRegistration, bool) {
for _, registry := range m.registries {
registration, ok := registry.TryGetSingleServiceRegistration(serviceType)
Expand All @@ -18,6 +19,7 @@ func (m *multiRegistryAccessor) TryGetSingleServiceRegistration(serviceType type
return nil, false
}

// TryGetServiceRegistrations tries to retrieve all service registrations for the given service type from multiple registries.
func (m *multiRegistryAccessor) TryGetServiceRegistrations(serviceType types.ServiceType) (types.ServiceRegistrationList, bool) {
for _, registry := range m.registries {
registration, ok := registry.TryGetServiceRegistrations(serviceType)
Expand All @@ -30,6 +32,7 @@ func (m *multiRegistryAccessor) TryGetServiceRegistrations(serviceType types.Ser

var _ types.ServiceRegistryAccessor = &multiRegistryAccessor{}

// NewMultiRegistryAccessor creates a new ServiceRegistryAccessor that aggregates multiple registries.
func NewMultiRegistryAccessor(registries ...types.ServiceRegistryAccessor) types.ServiceRegistryAccessor {
serviceRegistries := make([]types.ServiceRegistryAccessor, 0)
serviceRegistries = append(serviceRegistries, registries...)
Expand Down
9 changes: 9 additions & 0 deletions pkg/registration/service_registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func newTypeInfo(t types.ServiceType) typeInfo {
}
}

// InvokeActivator calls the activator function with the provided parameters and returns the created service instance.
func (s *serviceRegistration) InvokeActivator(params ...interface{}) (interface{}, error) {
var values []reflect.Value
if len(params) > 0 {
Expand All @@ -45,10 +46,12 @@ func (s *serviceRegistration) InvokeActivator(params ...interface{}) (interface{
return serviceInstance.Interface(), nil
}

// Id returns the unique identifier of this service registration.
func (s *serviceRegistration) Id() uint64 {
return s.id
}

// SetId sets the unique identifier for the service registration. Returns an error if the id is already set.
func (s *serviceRegistration) SetId(id uint64) error {
if s.id != 0 {
return errors.New("the id cannot be changed once set")
Expand All @@ -57,6 +60,7 @@ func (s *serviceRegistration) SetId(id uint64) error {
return nil
}

// IsSame Returns true, if the current instance equals the given service registration instance.
func (s *serviceRegistration) IsSame(other types.ServiceRegistration) bool {
sr, ok := other.(*serviceRegistration)
if ok {
Expand All @@ -71,10 +75,12 @@ func (s *serviceRegistration) IsSame(other types.ServiceRegistration) bool {
return false
}

// LifetimeScope returns the lifetime scope of the service registration.
func (s *serviceRegistration) LifetimeScope() types.LifetimeScope {
return s.lifetimeScope
}

// RequiredServiceTypes returns a slice of ServiceType representing the service dependencies.
func (s *serviceRegistration) RequiredServiceTypes() []types.ServiceType {
requiredTypes := make([]types.ServiceType, len(s.parameters))
for i, p := range s.parameters {
Expand All @@ -83,10 +89,12 @@ func (s *serviceRegistration) RequiredServiceTypes() []types.ServiceType {
return requiredTypes
}

// ServiceType returns the service type of the service registration.
func (s *serviceRegistration) ServiceType() types.ServiceType {
return s.serviceType.t
}

// String returns a string representation of the service registration, including the typename and its activator parameter types.
func (s *serviceRegistration) String() string {

buffer := strings.Builder{}
Expand All @@ -99,6 +107,7 @@ func (s *serviceRegistration) String() string {
return buffer.String()
}

// CreateServiceRegistration creates a service registration instance from the given activator function and lifetime scope.
func CreateServiceRegistration(activatorFunc any, lifetimeScope types.LifetimeScope) (types.ServiceRegistrationSetup, error) {
value := reflect.ValueOf(activatorFunc)

Expand Down
6 changes: 6 additions & 0 deletions pkg/registration/service_registration_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@ type serviceRegistrationList struct {
m sync.RWMutex
}

// IsEmpty Returns true if the list contains no registrations, otherwise false.
func (s *serviceRegistrationList) IsEmpty() bool {
return len(s.registrations) == 0
}

// Registrations returns a slice of ServiceRegistration representing the current registrations in the list.
func (s *serviceRegistrationList) Registrations() []types.ServiceRegistration {
s.m.RLock()
defer s.m.RUnlock()
return s.registrations
}

// AddRegistration adds a new service registration to the list.
// It returns an ErrorTypeAlreadyRegistered error if the registration already exists.
func (s *serviceRegistrationList) AddRegistration(registration types.ServiceRegistrationSetup) error {

s.m.Lock()
Expand All @@ -44,12 +48,14 @@ func (s *serviceRegistrationList) AddRegistration(registration types.ServiceRegi
return nil
}

// Id returns the unique identifier of the service registration list.
func (s *serviceRegistrationList) Id() uint64 {
return s.id
}

var _ types.ServiceRegistrationList = &serviceRegistrationList{}

// NewServiceRegistrationList creates a new service registration list instance.
func NewServiceRegistrationList(sequence core.ServiceIdSequence) types.ServiceRegistrationList {
id := sequence.Next()
return &serviceRegistrationList{
Expand Down
8 changes: 6 additions & 2 deletions pkg/resolving/activate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ import (
"github.com/matzefriedrich/parsley/pkg/types"
)

// Activate attempts to create and return an instance of the requested type using the provided resolver.
// This method can be used to instantiate service objects of unregistered types. The specified activator function can
// have parameters to demand service instances for registered service types.
// See https://matzefriedrich.github.io/parsley-docs/resolving/resolve-live-services/ for further information.
func Activate[T any](resolver types.Resolver, ctx context.Context, activatorFunc any, options ...types.ResolverOptionsFunc) (T, error) {

var nilInstance T

lifetimeScope := types.LifetimeTransient
registration, registrationErr := registration.CreateServiceRegistration(activatorFunc, lifetimeScope)
serviceRegistration, registrationErr := registration.CreateServiceRegistration(activatorFunc, lifetimeScope)
if registrationErr != nil {
return nilInstance, types.NewResolverError(types.ErrorCannotCreateInstanceOfUnregisteredType, types.WithCause(registrationErr))
}

serviceType := registration.ServiceType()
serviceType := serviceRegistration.ServiceType()
resolveActivatorFuncOption := func(registry types.ServiceRegistry) error {
return registry.Register(activatorFunc, lifetimeScope)
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/resolving/named_service_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
"github.com/matzefriedrich/parsley/pkg/types"
)

// NamedServiceResolverActivatorFunc defines a function for resolving named services.
type NamedServiceResolverActivatorFunc[T any] func(types.Resolver) func(string) (T, error)

// CreateNamedServiceResolverActivatorFunc creates a NamedServiceResolverActivatorFunc for resolving named services.
func CreateNamedServiceResolverActivatorFunc[T any]() NamedServiceResolverActivatorFunc[T] {
return func(resolver types.Resolver) func(string) (T, error) {
var nilInstance T
Expand Down
6 changes: 6 additions & 0 deletions pkg/resolving/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type resolver struct {
globalInstances *core.InstanceBag
}

// ResolveRequiredServices resolves all registered services of a specified type T using the given resolver and context.
func ResolveRequiredServices[T any](resolver types.Resolver, ctx context.Context) ([]T, error) {
t := reflect.TypeOf((*T)(nil)).Elem()
switch t.Kind() {
Expand All @@ -37,6 +38,8 @@ func ResolveRequiredServices[T any](resolver types.Resolver, ctx context.Context
return result, err
}

// ResolveRequiredService resolves a single service instance of the specified type using the given resolver and context.
// The method can return the following errors: ErrorCannotResolveService, ErrorAmbiguousServiceInstancesResolved.
func ResolveRequiredService[T any](resolver types.Resolver, ctx context.Context) (T, error) {
var nilInstance T
services, err := ResolveRequiredServices[T](resolver, ctx)
Expand All @@ -51,6 +54,7 @@ func ResolveRequiredService[T any](resolver types.Resolver, ctx context.Context)
return nilInstance, types.NewResolverError(types.ErrorCannotResolveService)
}

// NewResolver creates and returns a new Resolver instance based on the provided ServiceRegistry.
func NewResolver(registry types.ServiceRegistry) types.Resolver {
r := &resolver{
registry: registry,
Expand Down Expand Up @@ -90,10 +94,12 @@ func (r *resolver) createResolverRegistryAccessor(resolverOptions ...types.Resol
return r.registry, nil
}

// Resolve returns a list of instances associated with the specified service type.
func (r *resolver) Resolve(ctx context.Context, serviceType types.ServiceType) ([]interface{}, error) {
return r.ResolveWithOptions(ctx, serviceType)
}

// ResolveWithOptions resolves instances for the given service type with the provided resolver options.
func (r *resolver) ResolveWithOptions(ctx context.Context, serviceType types.ServiceType, resolverOptions ...types.ResolverOptionsFunc) ([]interface{}, error) {

registry, registryErr := r.createResolverRegistryAccessor(resolverOptions...)
Expand Down
1 change: 1 addition & 0 deletions pkg/resolving/resolver_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func applyResolverOptions(registry types.ServiceRegistry, options ...types.Resol
return nil
}

// WithInstance Creates a ResolverOptionsFunc that registers a specific instance of a type T with a service registry to be resolved as a singleton.
func WithInstance[T any](instance T) types.ResolverOptionsFunc {
return func(registry types.ServiceRegistry) error {
err := registration.RegisterInstance[T](registry, instance)
Expand Down
1 change: 1 addition & 0 deletions pkg/resolving/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/matzefriedrich/parsley/internal/core"
)

// NewScopedContext creates a new context with an associated service instance map, useful for managing service lifetimes within scope.
func NewScopedContext(ctx context.Context) context.Context {
instances := make(map[uint64]interface{})
return context.WithValue(ctx, core.ParsleyContext, instances)
Expand Down
4 changes: 4 additions & 0 deletions pkg/types/dependency_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ const (
)

var (
// ErrInstanceAlreadySet is returned when there is an attempt to set an instance that is already set.
ErrInstanceAlreadySet = errors.New(ErrorInstanceAlreadySet)
)

// DependencyError represents an error that occurs due to a missing or failed dependency.
// This error type encapsulates a ParsleyError.
type DependencyError struct {
ParsleyError
}

// NewDependencyError creates a new DependencyError with the provided message.
func NewDependencyError(msg string) error {
err := DependencyError{ParsleyError{Msg: msg}}
return err
Expand Down
Loading

0 comments on commit 5aca612

Please sign in to comment.