github.com/Aoi-hosizora/ahlib@v1.5.1-0.20230404072829-241b93cf91c7/xmodule/xmodule.go (about)

     1  package xmodule
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sync"
     7  )
     8  
     9  // ModuleName represents a global module name, and it could not be empty, '-' and '~'.
    10  type ModuleName string
    11  
    12  // String returns the string value of ModuleName.
    13  func (m ModuleName) String() string {
    14  	return string(m)
    15  }
    16  
    17  // mkey represents the key type of module map used in ModuleContainer, currently these fields are exclusive.
    18  type mkey struct {
    19  	name ModuleName   // by name
    20  	typ  reflect.Type // by type or intf
    21  }
    22  
    23  // nameKey returns a mkey with given ModuleName.
    24  func nameKey(name ModuleName) mkey {
    25  	return mkey{name: name}
    26  }
    27  
    28  // typeKey returns a mkey with given reflect.Type.
    29  func typeKey(typ reflect.Type) mkey {
    30  	return mkey{typ: typ}
    31  }
    32  
    33  // mkeyFromField returns a mkey with given field information.
    34  func mkeyFromField(fieldTag string, fieldType reflect.Type) mkey {
    35  	if fieldTag != "~" {
    36  		return mkey{name: ModuleName(fieldTag)} // by name -> use field tag
    37  	}
    38  	return mkey{typ: fieldType} // by type or intf -> use field type
    39  }
    40  
    41  // String returns the string value of mkey.
    42  func (m mkey) String() string {
    43  	if m.name != "" {
    44  		return fmt.Sprintf("name:%s", m.name.String())
    45  	}
    46  	if m.typ != nil {
    47  		return fmt.Sprintf("type:%s", m.typ.String())
    48  	}
    49  	return "<invalid>"
    50  }
    51  
    52  // ModuleContainer represents a module container, modules will be stored in a single map using its ModuleName (ProvideByName) or its
    53  // reflect.Type (ProvideByType or ProvideByIntf).
    54  type ModuleContainer struct {
    55  	modules map[mkey]interface{}
    56  	mu      sync.RWMutex
    57  	logger  Logger
    58  }
    59  
    60  // NewModuleContainer creates an empty ModuleContainer, using DefaultLogger with LogAll flag and default formats.
    61  func NewModuleContainer() *ModuleContainer {
    62  	return &ModuleContainer{
    63  		modules: make(map[mkey]interface{}),
    64  		logger:  DefaultLogger(LogAll, nil, nil),
    65  	}
    66  }
    67  
    68  // SetLogger sets given Logger for ModuleContainer, default logger can be got from DefaultLogger.
    69  //
    70  // Example:
    71  // 	SetLogger(DefaultLogger(LogAll))    // logs all messages (default)
    72  // 	SetLogger(DefaultLogger(LogSilent)) // disable all logger
    73  func (m *ModuleContainer) SetLogger(logger Logger) {
    74  	m.logger = logger
    75  }
    76  
    77  // ================
    78  // ensure functions
    79  // ================
    80  
    81  const (
    82  	panicInvalidModuleName   = "xmodule: invalid module name (empty, '-' and '~')"
    83  	panicNilModule           = "xmodule: nil module"
    84  	panicInvalidInterfacePtr = "xmodule: invalid interface pointer"
    85  	panicNotImplemented      = "xmodule: module does not implement the interface"
    86  	panicModuleNotFound      = "xmodule: module not found"
    87  )
    88  
    89  // ensureModuleName checks given ModuleName, panics if using invalid name, that is empty, '-' and '~'.
    90  func ensureModuleName(name ModuleName) {
    91  	if name == "" || name == "-" || name == "~" {
    92  		panic(panicInvalidModuleName)
    93  	}
    94  }
    95  
    96  // ensureModuleType checks whether given module is nil, panics if not, otherwise returns the reflect.Type.
    97  func ensureModuleType(module interface{}) reflect.Type {
    98  	if module == nil {
    99  		panic(panicNilModule)
   100  	}
   101  	return reflect.TypeOf(module)
   102  }
   103  
   104  // ensureInterfacePtr checks whether given value is an interface pointer, panics if not, otherwise returns the interface reflect.Type.
   105  func ensureInterfacePtr(interfacePtr interface{}) reflect.Type {
   106  	if interfacePtr == nil {
   107  		panic(panicInvalidInterfacePtr)
   108  	}
   109  	typ := reflect.TypeOf(interfacePtr)
   110  	if typ.Kind() != reflect.Ptr {
   111  		panic(panicInvalidInterfacePtr)
   112  	}
   113  	typ = typ.Elem() // interface type
   114  	if typ.Kind() != reflect.Interface {
   115  		panic(panicInvalidInterfacePtr)
   116  	}
   117  	return typ
   118  }
   119  
   120  // ensureModuleTypeWithInterface checks whether given value is nil, and whether it implements given interface type, panics if not, otherwise
   121  // returns its reflect.Type.
   122  func ensureModuleTypeWithInterface(moduleImpl interface{}, interfaceType reflect.Type) reflect.Type {
   123  	typ := ensureModuleType(moduleImpl) // module type
   124  	if !typ.Implements(interfaceType) {
   125  		panic(panicNotImplemented)
   126  	}
   127  	return typ
   128  }
   129  
   130  // =============================
   131  // methods: Provide, Remove, Get
   132  // =============================
   133  
   134  // ProvideByName provides a module using given ModuleName, panics when using invalid module name or nil module.
   135  //
   136  // Example:
   137  // 	m := NewModuleContainer()
   138  // 	m.ProvideByName(ModuleName("module"), &Module{})
   139  // 	module, ok := m.GetByName(ModuleName("module"))
   140  // 	module := m.MustGetByName(ModuleName("module"))
   141  // 	removed := m.RemoveByName(ModuleName("module"))
   142  func (m *ModuleContainer) ProvideByName(name ModuleName, module interface{}) {
   143  	ensureModuleName(name)
   144  	typ := ensureModuleType(module)
   145  	m.mu.Lock()
   146  	m.modules[nameKey(name)] = module
   147  	m.mu.Unlock()
   148  	m.logger.PrvName(name.String(), typ.String())
   149  }
   150  
   151  // ProvideByType provides a module using its type, panics when using nil module.
   152  //
   153  // Example:
   154  // 	m := NewModuleContainer()
   155  // 	m.ProvideByType(&Module{})
   156  // 	module, ok := m.GetByType(&Module{})
   157  // 	module := m.MustGetByType(&Module{})
   158  // 	removed := m.RemoveByType(&Module{})
   159  func (m *ModuleContainer) ProvideByType(module interface{}) {
   160  	typ := ensureModuleType(module)
   161  	m.mu.Lock()
   162  	m.modules[typeKey(typ)] = module
   163  	m.mu.Unlock()
   164  	m.logger.PrvType(typ.String())
   165  }
   166  
   167  // ProvideByIntf provides a module using given interface pointer type, such as `(*Interface)(nil)` or `new(Interface)`, panics when using
   168  // invalid interface pointer or nil module.
   169  //
   170  // Example:
   171  // 	m := NewModuleContainer()
   172  // 	m.ProvideByIntf((*Interface)(nil), &Module{})
   173  // 	module, ok := m.GetByIntf((*Interface)(nil))
   174  // 	module := m.MustGetByIntf((*Interface)(nil))
   175  // 	removed := m.RemoveByIntf((*Interface)(nil))
   176  func (m *ModuleContainer) ProvideByIntf(interfacePtr interface{}, moduleImpl interface{}) {
   177  	intfType := ensureInterfacePtr(interfacePtr)                   // interface type
   178  	modType := ensureModuleTypeWithInterface(moduleImpl, intfType) // module type
   179  	m.mu.Lock()
   180  	m.modules[typeKey(intfType)] = moduleImpl
   181  	m.mu.Unlock()
   182  	m.logger.PrvIntf(intfType.String(), modType.String())
   183  }
   184  
   185  // RemoveByName removes a module with a ModuleName from container, return true if module existed before removing, panics when using invalid
   186  // module name.
   187  func (m *ModuleContainer) RemoveByName(name ModuleName) (removed bool) {
   188  	ensureModuleName(name)
   189  	m.mu.Lock()
   190  	l := len(m.modules)
   191  	delete(m.modules, nameKey(name))
   192  	removed = len(m.modules) != l
   193  	m.mu.Unlock()
   194  	return removed
   195  }
   196  
   197  // RemoveByType removes given module with its type from container, return true if module existed before removing, panics when using nil module.
   198  func (m *ModuleContainer) RemoveByType(moduleType interface{}) (removed bool) {
   199  	typ := ensureModuleType(moduleType)
   200  	m.mu.Lock()
   201  	l := len(m.modules)
   202  	delete(m.modules, typeKey(typ))
   203  	removed = len(m.modules) != l
   204  	m.mu.Unlock()
   205  	return removed
   206  }
   207  
   208  // RemoveByIntf removes a module with given interface pointer's type from container, return true if module existed before removing, panics when
   209  // using invalid interface pointer.
   210  func (m *ModuleContainer) RemoveByIntf(interfacePtr interface{}) (removed bool) {
   211  	intfType := ensureInterfacePtr(interfacePtr) // interface type
   212  	m.mu.Lock()
   213  	l := len(m.modules)
   214  	delete(m.modules, typeKey(intfType))
   215  	removed = len(m.modules) != l
   216  	m.mu.Unlock()
   217  	return removed
   218  }
   219  
   220  // GetByName returns the module provided by name, panics when using invalid module name.
   221  func (m *ModuleContainer) GetByName(name ModuleName) (module interface{}, exist bool) {
   222  	ensureModuleName(name)
   223  	m.mu.RLock()
   224  	module, exist = m.modules[nameKey(name)]
   225  	m.mu.RUnlock()
   226  	return module, exist
   227  }
   228  
   229  // MustGetByName returns a module provided by name, panics when using invalid module name or module not found.
   230  func (m *ModuleContainer) MustGetByName(name ModuleName) interface{} {
   231  	module, exist := m.GetByName(name)
   232  	if !exist {
   233  		panic(panicModuleNotFound)
   234  	}
   235  	return module
   236  }
   237  
   238  // GetByType returns a module provided by type, panics when using nil type.
   239  func (m *ModuleContainer) GetByType(moduleType interface{}) (module interface{}, exist bool) {
   240  	typ := ensureModuleType(moduleType)
   241  	m.mu.RLock()
   242  	module, exist = m.modules[typeKey(typ)]
   243  	m.mu.RUnlock()
   244  	return module, exist
   245  }
   246  
   247  // MustGetByType returns a module provided by type, panics when using nil type or module not found.
   248  func (m *ModuleContainer) MustGetByType(moduleType interface{}) interface{} {
   249  	module, exist := m.GetByType(moduleType)
   250  	if !exist {
   251  		panic(panicModuleNotFound)
   252  	}
   253  	return module
   254  }
   255  
   256  // GetByIntf returns a module by interface pointer, panics when using invalid interface pointer.
   257  func (m *ModuleContainer) GetByIntf(interfacePtr interface{}) (module interface{}, exist bool) {
   258  	intfType := ensureInterfacePtr(interfacePtr) // interface type
   259  	m.mu.RLock()
   260  	module, exist = m.modules[typeKey(intfType)]
   261  	m.mu.RUnlock()
   262  	return module, exist
   263  }
   264  
   265  // MustGetByIntf returns a module by interface pointer, panics when using invalid interface pointer or module not found.
   266  func (m *ModuleContainer) MustGetByIntf(interfacePtr interface{}) interface{} {
   267  	module, exist := m.GetByIntf(interfacePtr)
   268  	if !exist {
   269  		panic(panicModuleNotFound)
   270  	}
   271  	return module
   272  }
   273  
   274  // ======
   275  // global
   276  // ======
   277  
   278  // _mc is a global ModuleContainer.
   279  var _mc = NewModuleContainer()
   280  
   281  // SetLogger sets the Logger for ModuleContainer.
   282  //
   283  // Example:
   284  // 	SetLogger(DefaultLogger(LogAll))    // logs all messages (default)
   285  // 	SetLogger(DefaultLogger(LogSilent)) // disable all logger
   286  func SetLogger(logger Logger) {
   287  	_mc.SetLogger(logger)
   288  }
   289  
   290  // ProvideByName provides a module using given ModuleName, panics when using invalid module name or nil module.
   291  //
   292  // Example:
   293  // 	xmodule.ProvideByName(ModuleName("module"), &Module{})
   294  // 	module, ok := xmodule.GetByName(ModuleName("module"))
   295  // 	module := xmodule.MustGetByName(ModuleName("module"))
   296  // 	removed := xmodule.RemoveByName(ModuleName("module"))
   297  func ProvideByName(name ModuleName, module interface{}) {
   298  	_mc.ProvideByName(name, module)
   299  }
   300  
   301  // ProvideByType provides a module using its type, panics when using nil module.
   302  //
   303  // Example:
   304  // 	xmodule.ProvideByType(&Module{})
   305  // 	module, ok := xmodule.GetByType(&Module{})
   306  // 	module := xmodule.MustGetByType(&Module{})
   307  // 	removed := xmodule.RemoveByType(&Module{})
   308  func ProvideByType(module interface{}) {
   309  	_mc.ProvideByType(module)
   310  }
   311  
   312  // ProvideByIntf provides a module using given interface pointer type, such as `(*Interface)(nil)` or `new(Interface)`, panics when using
   313  // invalid interface pointer or nil module.
   314  //
   315  // Example:
   316  // 	xmodule.ProvideByIntf((*Interface)(nil), &Module{})
   317  // 	module, ok := xmodule.GetByIntf((*Interface)(nil))
   318  // 	module := xmodule.MustGetByIntf((*Interface)(nil))
   319  // 	removed := xmodule.RemoveByIntf((*Interface)(nil))
   320  func ProvideByIntf(interfacePtr interface{}, moduleImpl interface{}) {
   321  	_mc.ProvideByIntf(interfacePtr, moduleImpl)
   322  }
   323  
   324  // RemoveByName removes a module with a ModuleName from container, return true if module existed before removing, panics when using invalid
   325  // module name.
   326  func RemoveByName(name ModuleName) (removed bool) {
   327  	return _mc.RemoveByName(name)
   328  }
   329  
   330  // RemoveByType removes given module with its type from container, return true if module existed before removing, panics when using nil module.
   331  func RemoveByType(module interface{}) (removed bool) {
   332  	return _mc.RemoveByType(module)
   333  }
   334  
   335  // RemoveByIntf removes a module with given interface pointer's type from container, return true if module existed before removing, panics when
   336  // using invalid interface pointer.
   337  func RemoveByIntf(interfacePtr interface{}) (removed bool) {
   338  	return _mc.RemoveByIntf(interfacePtr)
   339  }
   340  
   341  // GetByName returns the module provided by name, panics when using invalid module name.
   342  func GetByName(name ModuleName) (module interface{}, exist bool) {
   343  	return _mc.GetByName(name)
   344  }
   345  
   346  // MustGetByName returns a module provided by name, panics when using invalid module name or module not found.
   347  func MustGetByName(name ModuleName) interface{} {
   348  	return _mc.MustGetByName(name)
   349  }
   350  
   351  // GetByType returns a module provided by type, panics when using nil type.
   352  func GetByType(moduleType interface{}) (module interface{}, exist bool) {
   353  	return _mc.GetByType(moduleType)
   354  }
   355  
   356  // MustGetByType returns a module provided by type, panics when using nil type or module not found.
   357  func MustGetByType(moduleType interface{}) interface{} {
   358  	return _mc.MustGetByType(moduleType)
   359  }
   360  
   361  // GetByIntf returns a module by interface pointer, panics when using invalid interface pointer.
   362  func GetByIntf(interfacePtr interface{}) (module interface{}, exist bool) {
   363  	return _mc.GetByIntf(interfacePtr)
   364  }
   365  
   366  // MustGetByIntf returns a module by interface pointer, panics when using invalid interface pointer or module not found.
   367  func MustGetByIntf(interfacePtr interface{}) interface{} {
   368  	return _mc.MustGetByIntf(interfacePtr)
   369  }
   370  
   371  // Inject injects into given injectee's module fields, returns error if there are some fields can not be injected (possible reasons: specific
   372  // module is not found, module type mismatches with field), panics when injectee passed is nil or not a structure pointer. Note that if error
   373  // is returned, remaining fields will still be injected as usual.
   374  //
   375  // Example:
   376  // 	type Struct struct {
   377  // 		unexportedField string                 // -> ignore (unexported)
   378  // 		ExportedField1  string                 // -> ignore (no module tag)
   379  // 		ExportedField2  string `module:""`     // -> ignore (module tag is empty)
   380  // 		ExportedField3  string `module:"-"`    // -> ignore (module tag is "-")
   381  // 		ExportedField4  string `module:"name"` // -> inject by name
   382  // 		ExportedField5  string `module:"~"`    // -> inject by type or intf
   383  // 	}
   384  // 	m := NewModuleContainer()
   385  // 	all := Inject(&Struct{})
   386  func Inject(injectee interface{}) error {
   387  	return _mc.Inject(injectee)
   388  }
   389  
   390  // MustInject injects into given injectee's module fields, panics when injectee passed is nil or not a structure pointer, or there are some fields
   391  // can not be injected for several reasons. Note that remaining fields will stop injecting once error happened. See Inject for more details.
   392  func MustInject(injectee interface{}) {
   393  	_mc.MustInject(injectee)
   394  }
   395  
   396  // AutoProvide processes with given ModuleProvider-s, injects them if necessary (must be a pointer of struct), and provides them in dependency
   397  // order, returns error if some fields from providers can not be injected (see Inject for more details), or some dependent modules is not found,
   398  // or cycle dependency happens, panics when using invalid provider.
   399  //
   400  // Example:
   401  // 	wellKnownList := []int{...}
   402  // 	type Service struct {
   403  // 		WellKnownList  []int     `module:"list"`
   404  // 		AnotherService *ServiceB `module:"~"`
   405  // 		Implement      Interface `module:"~"`
   406  // 		LocalVariable  string // a local variable for Service
   407  // 	}
   408  // 	m := NewModuleContainer()
   409  // 	_ = m.AutoProvide(
   410  // 		TypeProvider(&Service{LocalVariable: "..."}),
   411  // 		TypeProvider(&ServiceB{...}),
   412  // 		NameProvider("list", wellKnownList),
   413  // 		IntfProvider((*Interface)(nil), &Implement{}),
   414  // 	)
   415  // 	_ = m.MustGetByType(&Service{}).(*Service)
   416  func AutoProvide(providers ...*ModuleProvider) error {
   417  	return _mc.AutoProvide(providers...)
   418  }
   419  
   420  // MustAutoProvide processes with given ModuleProvider-s, injects them if necessary and provides them in dependency order, panics when error happens.
   421  // See AutoProvide for more details.
   422  func MustAutoProvide(providers ...*ModuleProvider) {
   423  	_mc.MustAutoProvide(providers...)
   424  }