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  }