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 }