github.com/alimy/mir/v4@v4.1.0/internal/parser/parser.go (about) 1 // Copyright 2020 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 parser 6 7 import ( 8 "errors" 9 "sync" 10 11 "github.com/alimy/mir/v4/core" 12 "github.com/alimy/mir/v4/internal/reflex" 13 "github.com/alimy/mir/v4/internal/utils" 14 ) 15 16 var ( 17 // defaultTag indicate default mir's struct tag name 18 defaultTag = "mir" 19 defautlMethodTag = "method" 20 ) 21 22 func init() { 23 core.RegisterParsers(&mirParser{ 24 engineInfo: &core.EngineInfo{}, 25 tagName: defaultTag, 26 }) 27 } 28 29 // mirParser parse for struct tag 30 type mirParser struct { 31 engineInfo *core.EngineInfo 32 tagName string 33 watchCtxDone bool 34 noneQuery bool 35 } 36 37 // Name name of parser 38 func (p *mirParser) Name() string { 39 return core.ParserStructTag 40 } 41 42 // Init init parser 43 func (p *mirParser) Init(opts *core.ParserOpts) error { 44 if opts == nil { 45 return errors.New("init opts is nil") 46 } 47 if opts.EngineInfo != nil { 48 p.engineInfo = opts.EngineInfo 49 } 50 p.tagName = opts.DefaultTag 51 p.watchCtxDone = opts.WatchCtxDone 52 p.noneQuery = opts.NoneQuery 53 if p.tagName == "" { 54 p.tagName = defaultTag 55 } 56 return nil 57 } 58 59 // Parse serial parse interface defined object entries 60 func (p *mirParser) Parse(entries []any) (core.Descriptors, error) { 61 if len(entries) == 0 { 62 return nil, errors.New("entries is empty") 63 } 64 r := reflex.NewReflex(p.engineInfo, p.tagName, p.watchCtxDone, p.noneQuery) 65 return r.Parse(entries) 66 } 67 68 // ParseContext concurrent parse interface defined object entries 69 func (p *mirParser) ParseContext(ctx core.MirCtx, entries []any) { 70 _, ifaceSink := ctx.Pipe() 71 muxSet := utils.NewMuxSet() 72 73 wg := &sync.WaitGroup{} 74 for _, entry := range entries { 75 wg.Add(1) 76 go func(ctx core.MirCtx, wg *sync.WaitGroup, ifaceSink chan<- *core.IfaceDescriptor, entry any) { 77 defer wg.Done() 78 79 r := reflex.NewReflex(p.engineInfo, p.tagName, p.watchCtxDone, p.noneQuery) 80 iface, err := r.IfaceFrom(entry) 81 if err != nil { 82 core.Logus("ifaceFrom error: %s", err) 83 ctx.Cancel(err) 84 return 85 } 86 // no actual fields so just continue 87 if len(iface.Fields) == 0 { 88 return 89 } 90 core.Logus("parsed iface: %s.%s", iface.PkgName, iface.TypeName) 91 if err = muxSet.Add(iface.Group + iface.TypeName); err != nil { 92 core.Logus("muxSet.Add error: %s", err) 93 ctx.Cancel(err) 94 return 95 } 96 ifaceSink <- iface 97 core.Logus("delivered iface: %s.%s", iface.PkgName, iface.TypeName) 98 }(ctx, wg, ifaceSink, entry) 99 } 100 wg.Wait() 101 102 ctx.ParserDone() 103 } 104 105 // Clone return a copy of Parser 106 func (p *mirParser) Clone() core.Parser { 107 return &mirParser{ 108 tagName: p.tagName, 109 } 110 }