github.com/alimy/mir/v4@v4.1.0/engine/engine.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 engine
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"runtime"
    11  	"sync"
    12  
    13  	"github.com/alimy/mir/v4/core"
    14  	"github.com/alimy/mir/v4/internal"
    15  )
    16  
    17  var (
    18  	mu         = &sync.Mutex{}
    19  	mirEntries = make([]any, 0, 8)
    20  )
    21  
    22  // AddEntry add mir's entry list.
    23  func AddEntry(entries ...any) {
    24  	mu.Lock()
    25  	defer mu.Unlock()
    26  
    27  	addEntries(entries...)
    28  }
    29  
    30  // Entry add mir's entry by a type
    31  func Entry[T any]() {
    32  	mu.Lock()
    33  	defer mu.Unlock()
    34  
    35  	addEntries(new(T))
    36  }
    37  
    38  // Generate generate interface code from mir's iface entry
    39  func Generate(opts core.Options, entries ...any) (err error) {
    40  	mu.Lock()
    41  	defer mu.Unlock()
    42  
    43  	addEntries(entries...)
    44  	if len(mirEntries) == 0 {
    45  		return errors.New("mir entries is empty maybe need add entries first")
    46  	}
    47  
    48  	initOpts := core.InitFrom(opts)
    49  	p := core.ParserByName(initOpts.ParserName)
    50  	// use default parser when not set parser name from options
    51  	if p == nil {
    52  		p = core.DefaultParser()
    53  	}
    54  	if err = p.Init(initOpts.ParserOpts()); err != nil {
    55  		return
    56  	}
    57  
    58  	g := core.GeneratorByName(initOpts.GeneratorName)
    59  	if g == nil {
    60  		return fmt.Errorf("unknow or yet not supported generator that name of %s", initOpts.GeneratorName)
    61  	}
    62  	if err = g.Init(initOpts.GeneratorOpts()); err != nil {
    63  		return
    64  	}
    65  
    66  	core.Logus("run in %s", initOpts.RunMode)
    67  	switch initOpts.RunMode {
    68  	case core.InSerialDebugMode, core.InSerialMode:
    69  		err = doInSerial(p, g, mirEntries)
    70  	case core.InConcurrentDebugMode, core.InConcurrentMode:
    71  		err = doInConcurrent(p, g, mirEntries)
    72  	}
    73  	return err
    74  }
    75  
    76  func addEntries(entries ...any) {
    77  	mirEntries = append(mirEntries, entries...)
    78  }
    79  
    80  func doInSerial(p core.Parser, g core.Generator, entries []any) error {
    81  	descriptors, err := p.Parse(entries)
    82  	if err == nil {
    83  		return g.Generate(descriptors)
    84  	}
    85  	return err
    86  }
    87  
    88  func doInConcurrent(p core.Parser, g core.Generator, entries []any) error {
    89  	numCPU := runtime.NumCPU()
    90  	runtime.GOMAXPROCS(numCPU)
    91  	core.Logus("set GOMAXPROCS: %d", numCPU)
    92  
    93  	ctx := internal.NewMirCtx(16)
    94  
    95  	go p.ParseContext(ctx, entries)
    96  	go g.GenerateContext(ctx)
    97  
    98  	return ctx.Wait()
    99  }