github.com/alimy/mir/v4@v4.1.0/core/core.go (about) 1 // Copyright 2019 Michael Li <alimy@gility.net>. All rights reserved. 2 // Use of this source code is governed by Apache License 2.0 that 3 // can be found in the LICENSE file. 4 5 package core 6 7 import ( 8 "context" 9 "log" 10 11 "github.com/alimy/mir/v4/assert" 12 ) 13 14 const ( 15 // run mode list 16 InSerialMode runMode = iota 17 InConcurrentMode 18 InSerialDebugMode 19 InConcurrentDebugMode 20 21 // generator Names 22 GeneratorGin = "gin" 23 GeneratorChi = "chi" 24 GeneratorMux = "mux" 25 GeneratorHertz = "hertz" 26 GeneratorEcho = "echo" 27 GeneratorIris = "iris" 28 GeneratorFiber = "fiber" 29 GeneratorMacaron = "macaron" 30 GeneratorHttpRouter = "httprouter" 31 32 // parser Names 33 ParserStructTag = "structTag" 34 ) 35 36 var ( 37 // generators generator list 38 generators = make(map[string]Generator, 4) 39 40 // parsers parser list 41 parsers = make(map[string]Parser, 1) 42 43 // inDebug whether in debug mode 44 inDebug bool 45 ) 46 47 // runMode indicate process mode (InSerialMode | InSerialDebugMode | InConcurrentMode | InConcurrentDebugMode) 48 type runMode uint8 49 50 // InitOpts use for generator or parser init 51 type InitOpts struct { 52 RunMode runMode 53 GeneratorName string 54 ParserName string 55 SinkPath string 56 DefaultTag string 57 EnginePkgName string 58 EngineImportAlias string 59 WatchCtxDone bool 60 NoneQuery bool 61 Cleanup bool 62 } 63 64 // ParserOpts used for initial parser 65 type ParserOpts struct { 66 EngineInfo *EngineInfo 67 DefaultTag string 68 WatchCtxDone bool 69 NoneQuery bool 70 } 71 72 // GeneratorOpts used for initial generator 73 type GeneratorOpts struct { 74 SinkPath string 75 Cleanup bool 76 } 77 78 // Option pass option to custom run behavior 79 type Option interface { 80 apply(opts *InitOpts) 81 } 82 83 // Options generator options 84 type Options []Option 85 86 // InitOpts return an initOpts instance 87 func (opts Options) InitOpts() *InitOpts { 88 res := defaultInitOpts() 89 for _, opt := range opts { 90 opt.apply(res) 91 } 92 return res 93 } 94 95 // ParserOpts return a ParserOpts instance 96 func (opts *InitOpts) ParserOpts() *ParserOpts { 97 return &ParserOpts{ 98 DefaultTag: opts.DefaultTag, 99 WatchCtxDone: opts.WatchCtxDone, 100 NoneQuery: opts.NoneQuery, 101 EngineInfo: &EngineInfo{ 102 PkgName: opts.EnginePkgName, 103 ImportAlias: opts.EngineImportAlias, 104 }, 105 } 106 } 107 108 // GeneratorOpts return a GeneratorOpts 109 func (opts *InitOpts) GeneratorOpts() *GeneratorOpts { 110 return &GeneratorOpts{ 111 SinkPath: opts.SinkPath, 112 Cleanup: opts.Cleanup, 113 } 114 } 115 116 // optFunc used for convert function to Option interface 117 type optFunc func(opts *InitOpts) 118 119 func (f optFunc) apply(opts *InitOpts) { 120 f(opts) 121 } 122 123 // Parser parse entries 124 type Parser interface { 125 Name() string 126 Init(opts *ParserOpts) error 127 Parse(entries []any) (Descriptors, error) 128 ParseContext(ctx MirCtx, entries []any) 129 Clone() Parser 130 } 131 132 // Generator generate interface code for engine 133 type Generator interface { 134 Name() string 135 Init(opts *GeneratorOpts) error 136 Generate(Descriptors) error 137 GenerateContext(ctx MirCtx) 138 Clone() Generator 139 } 140 141 // MirCtx mir's concurrent parser/generator context 142 type MirCtx interface { 143 context.Context 144 Cancel(err error) 145 ParserDone() 146 GeneratorDone() 147 Wait() error 148 Capcity() int 149 Pipe() (<-chan *IfaceDescriptor, chan<- *IfaceDescriptor) 150 } 151 152 // String runMode describe 153 func (m runMode) String() string { 154 res := "not support mode" 155 switch m { 156 case InSerialMode: 157 res = "serial mode" 158 case InSerialDebugMode: 159 res = "serial debug mode" 160 case InConcurrentMode: 161 res = "concurrent mode" 162 case InConcurrentDebugMode: 163 res = "concurrent debug mode" 164 } 165 return res 166 } 167 168 // RunMode set run mode option 169 func RunMode(mode runMode) Option { 170 return optFunc(func(opts *InitOpts) { 171 opts.RunMode = mode 172 }) 173 } 174 175 // GeneratorName set generator name option 176 func GeneratorName(name string) Option { 177 return optFunc(func(opts *InitOpts) { 178 opts.GeneratorName = name 179 }) 180 } 181 182 // UseGin use Gin engine generator 183 func UseGin() Option { 184 return optFunc(func(opts *InitOpts) { 185 opts.GeneratorName = GeneratorGin 186 }) 187 } 188 189 // UseChi use Chi engine generator 190 func UseChi() Option { 191 return optFunc(func(opts *InitOpts) { 192 opts.GeneratorName = GeneratorChi 193 }) 194 } 195 196 // UseMux use Mux engine generator 197 func UseMux() Option { 198 return optFunc(func(opts *InitOpts) { 199 opts.GeneratorName = GeneratorMux 200 }) 201 } 202 203 // UseHertz use Hertz engine generator 204 func UseHertz() Option { 205 return optFunc(func(opts *InitOpts) { 206 opts.GeneratorName = GeneratorHertz 207 }) 208 } 209 210 // UseEcho use Echo engine generator 211 func UseEcho() Option { 212 return optFunc(func(opts *InitOpts) { 213 opts.GeneratorName = GeneratorEcho 214 }) 215 } 216 217 // UseIris use Iris engine generator 218 func UseIris() Option { 219 return optFunc(func(opts *InitOpts) { 220 opts.GeneratorName = GeneratorIris 221 }) 222 } 223 224 // UseFiber use Fiber engine generator 225 func UseFiber() Option { 226 return optFunc(func(opts *InitOpts) { 227 opts.GeneratorName = GeneratorFiber 228 }) 229 } 230 231 // UseMacaron use Macaron engine generator 232 func UseMacaron() Option { 233 return optFunc(func(opts *InitOpts) { 234 opts.GeneratorName = GeneratorMacaron 235 }) 236 } 237 238 // UseHttpRouter use HttpRouter engine generator 239 func UseHttpRouter() Option { 240 return optFunc(func(opts *InitOpts) { 241 opts.GeneratorName = GeneratorHttpRouter 242 }) 243 } 244 245 // ParserName set parser name option 246 func ParserName(name string) Option { 247 return optFunc(func(opts *InitOpts) { 248 opts.ParserName = name 249 }) 250 } 251 252 // SinkPath set generated code out directory 253 func SinkPath(path string) Option { 254 return optFunc(func(opts *InitOpts) { 255 opts.SinkPath = path 256 }) 257 } 258 259 // AssertType[T] register assert.TypeAssertor for custom T type 260 func AssertType[T any]() Option { 261 return optFunc(func(_opts *InitOpts) { 262 assert.RegisterType[T]() 263 }) 264 } 265 266 // AssertType2[B, R] register assert.TypeAssertor for custom B(Binding) and R(Render) type 267 func AssertType2[B, R any]() Option { 268 return optFunc(func(_opts *InitOpts) { 269 assert.RegisterType2[B, R]() 270 }) 271 } 272 273 // AssertType3[B, P, R] register assert.TypeAssertor for custom B(Binding)/P(Params) and R(Render) type 274 func AssertType3[B, P, R any]() Option { 275 return optFunc(func(_opts *InitOpts) { 276 assert.RegisterType3[B, P, R]() 277 }) 278 } 279 280 // AssertType4[C, T] register assert.TypeAssertor for custom C, T type 281 func AssertType4[C, T any]() Option { 282 return optFunc(func(_opts *InitOpts) { 283 assert.RegisterType4[C, T]() 284 }) 285 } 286 287 // WatchCtxDone set generator whether watch context done when Register Servants in 288 // generated code. default watch context done. 289 func WatchCtxDone(enable bool) Option { 290 return optFunc(func(opts *InitOpts) { 291 opts.WatchCtxDone = enable 292 }) 293 } 294 295 // Cleanup set generator cleanup out first when re-generate code 296 func Cleanup(enable bool) Option { 297 return optFunc(func(opts *InitOpts) { 298 opts.Cleanup = enable 299 }) 300 } 301 302 // NoneQuery set parser whether parse query 303 func NoneQuery(enable bool) Option { 304 return optFunc(func(opts *InitOpts) { 305 opts.NoneQuery = enable 306 }) 307 } 308 309 // DefaultTag set parser's default struct field tag string key 310 func DefaultTag(tag string) Option { 311 return optFunc(func(opts *InitOpts) { 312 opts.DefaultTag = tag 313 }) 314 } 315 316 // EnginePkgName engine package name 317 func EnginePkgName(pkgName string) Option { 318 return optFunc(func(opts *InitOpts) { 319 opts.EnginePkgName = pkgName 320 }) 321 } 322 323 // EngineImportAlias import package alias name 324 func EngineImportAlias(name string) Option { 325 return optFunc(func(opts *InitOpts) { 326 opts.EngineImportAlias = name 327 }) 328 } 329 330 // RegisterGenerators register generators 331 func RegisterGenerators(gs ...Generator) { 332 for _, g := range gs { 333 if g != nil && g.Name() != "" { 334 generators[g.Name()] = g 335 } 336 } 337 } 338 339 // RegisterParsers register parsers 340 func RegisterParsers(ps ...Parser) { 341 for _, p := range ps { 342 if p != nil && p.Name() != "" { 343 parsers[p.Name()] = p 344 } 345 } 346 } 347 348 // GeneratorByName get a generator by name 349 func GeneratorByName(name string) Generator { 350 return generators[name] 351 } 352 353 // DefaultGenerator get a default generator 354 func DefaultGenerator() Generator { 355 return generators[GeneratorGin] 356 } 357 358 // ParserByName get a parser by name 359 func ParserByName(name string) Parser { 360 return parsers[name] 361 } 362 363 // DefaultParser get a default parser 364 func DefaultParser() Parser { 365 return parsers[ParserStructTag] 366 } 367 368 // Logus print log info 369 func Logus(format string, v ...any) { 370 if inDebug { 371 log.Printf("[mir] "+format, v...) 372 } 373 } 374 375 // InitFrom initial from Options and return an InitOpts instance 376 func InitFrom(opts Options) *InitOpts { 377 var initOpts *InitOpts 378 if opts == nil { 379 initOpts = defaultInitOpts() 380 } else { 381 initOpts = opts.InitOpts() 382 } 383 384 switch initOpts.RunMode { 385 case InSerialDebugMode, InConcurrentDebugMode: 386 inDebug = true 387 default: 388 inDebug = false 389 } 390 391 return initOpts 392 } 393 394 func defaultInitOpts() *InitOpts { 395 return &InitOpts{ 396 RunMode: InSerialMode, 397 GeneratorName: GeneratorGin, 398 ParserName: ParserStructTag, 399 SinkPath: ".auto", 400 DefaultTag: "mir", 401 WatchCtxDone: true, 402 Cleanup: true, 403 } 404 }