github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/thrift/idl.go (about)

     1  /**
     2   * Copyright 2023 CloudWeGo Authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package thrift
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"math"
    24  	"math/rand"
    25  	"path/filepath"
    26  	"strings"
    27  	"time"
    28  
    29  	"github.com/cloudwego/dynamicgo/http"
    30  	"github.com/cloudwego/dynamicgo/internal/json"
    31  	"github.com/cloudwego/dynamicgo/internal/rt"
    32  	"github.com/cloudwego/dynamicgo/internal/util"
    33  	"github.com/cloudwego/dynamicgo/meta"
    34  	"github.com/cloudwego/thriftgo/parser"
    35  	"github.com/cloudwego/thriftgo/semantic"
    36  )
    37  
    38  const (
    39  	Request ParseTarget = iota
    40  	Response
    41  	Exception
    42  )
    43  
    44  // ParseTarget indicates the target to parse
    45  type ParseTarget uint8
    46  
    47  // Options is options for parsing thrift IDL.
    48  type Options struct {
    49  	// ParseServiceMode indicates how to parse service.
    50  	ParseServiceMode meta.ParseServiceMode
    51  
    52  	// MapFieldWay indicates StructDescriptor.FieldByKey() uses alias to map field.
    53  	// By default, we use alias to map, and alias always equals to field name if not given.
    54  	MapFieldWay meta.MapFieldWay
    55  
    56  	// ParseFieldRandomRate indicates whether to parse partial fields and is only used for mock test.
    57  	// The value means the possibility of randomly parse and embed one field into StructDescriptor.
    58  	// It must be within (0, 1], and 0 means always parse all fields.
    59  	ParseFieldRandomRate float64
    60  
    61  	// ParseEnumAsInt64 indicates whether to parse enum as I64 (default I32).
    62  	ParseEnumAsInt64 bool
    63  
    64  	// SetOptionalBitmap indicates to set bitmap for optional fields
    65  	SetOptionalBitmap bool
    66  
    67  	// UseDefaultValue indicates to parse and store default value defined on IDL fields.
    68  	UseDefaultValue bool
    69  
    70  	// ParseFunctionMode indicates to parse only response or request for a function
    71  	ParseFunctionMode meta.ParseFunctionMode
    72  
    73  	// EnableThriftBase indicates to explictly handle thrift/base (see README.md) fields.
    74  	// One field is identified as a thrift base if it satisfies **BOTH** of the following conditions:
    75  	//   1. Its type is 'base.Base' (for request base) or 'base.BaseResp' (for response base);
    76  	//   2. it is on the top layer of the root struct of one function.
    77  	EnableThriftBase bool
    78  
    79  	// PutNameSpaceToAnnotation indicates to extract the name-space of one type 
    80  	// and put it on the type's annotation. The annotion format is:
    81  	//   - Key: "thrift.name_space" (== NameSpaceAnnotationKey)
    82  	//   - Values: pairs of Language and Name. for example:
    83  	//      `namespace go base` will got ["go", "base"]
    84  	// NOTICE: at present, only StructDescriptor.Annotations() can get this
    85  	PutNameSpaceToAnnotation bool
    86  }
    87  
    88  // NewDefaultOptions creates a default Options.
    89  func NewDefaultOptions() Options {
    90  	return Options{}
    91  }
    92  
    93  // path := /a/b/c.thrift
    94  // includePath := ../d.thrift
    95  // result := /a/d.thrift
    96  func absPath(path, includePath string) string {
    97  	if filepath.IsAbs(includePath) {
    98  		return includePath
    99  	}
   100  	return filepath.Join(filepath.Dir(path), includePath)
   101  }
   102  
   103  // NewDescritorFromPath behaviors like NewDescritorFromPath, besides it uses DefaultOptions.
   104  func NewDescritorFromPath(ctx context.Context, path string, includeDirs ...string) (*ServiceDescriptor, error) {
   105  	return NewDefaultOptions().NewDescritorFromPath(ctx, path, includeDirs...)
   106  }
   107  
   108  // NewDescritorFromContent creates a ServiceDescriptor from a thrift path and its includes, which uses the given options.
   109  // The includeDirs is used to find the include files.
   110  func (opts Options) NewDescritorFromPath(ctx context.Context, path string, includeDirs ...string) (*ServiceDescriptor, error) {
   111  	tree, err := parser.ParseFile(path, includeDirs, true)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	svc, err := parse(ctx, tree, opts.ParseServiceMode, opts)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	return svc, nil
   120  }
   121  
   122  // NewDescritorFromContent creates a ServiceDescriptor from a thrift path and its includes, with specific methods.
   123  // If methods is empty, all methods will be parsed.
   124  // The includeDirs is used to find the include files.
   125  func (opts Options) NewDescriptorFromPathWithMethod(ctx context.Context, path string, includeDirs []string, methods ...string) (*ServiceDescriptor, error) {
   126  	tree, err := parser.ParseFile(path, includeDirs, true)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	svc, err := parse(ctx, tree, opts.ParseServiceMode, opts, methods...)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	return svc, nil
   135  }
   136  
   137  // NewDescritorFromContent behaviors like NewDescritorFromPath, besides it uses DefaultOptions.
   138  func NewDescritorFromContent(ctx context.Context, path, content string, includes map[string]string, isAbsIncludePath bool) (*ServiceDescriptor, error) {
   139  	return NewDefaultOptions().NewDescritorFromContent(ctx, path, content, includes, isAbsIncludePath)
   140  }
   141  
   142  // NewDescritorFromContent creates a ServiceDescriptor from a thrift content and its includes, which uses the default options.
   143  // path is the main thrift file path, content is the main thrift file content.
   144  // includes is the thrift file content map, and its keys are specific including thrift file path.
   145  // isAbsIncludePath indicates whether these keys of includes are absolute path. If true, the include path will be joined with the main thrift file path.
   146  func (opts Options) NewDescritorFromContent(ctx context.Context, path, content string, includes map[string]string, isAbsIncludePath bool) (*ServiceDescriptor, error) {
   147  	tree, err := parseIDLContent(path, content, includes, isAbsIncludePath)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	svc, err := parse(ctx, tree, opts.ParseServiceMode, opts)
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	return svc, nil
   156  }
   157  
   158  // NewDescritorFromContentWithMethod creates a ServiceDescriptor from a thrift content and its includes, but only parse specific methods.
   159  func (opts Options) NewDescriptorFromContentWithMethod(ctx context.Context, path, content string, includes map[string]string, isAbsIncludePath bool, methods ...string) (*ServiceDescriptor, error) {
   160  	tree, err := parseIDLContent(path, content, includes, isAbsIncludePath)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  	svc, err := parse(ctx, tree, opts.ParseServiceMode, opts, methods...)
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  	return svc, nil
   169  }
   170  
   171  func parseIDLContent(path, content string, includes map[string]string, isAbsIncludePath bool) (*parser.Thrift, error) {
   172  	tree, err := parser.ParseString(path, content)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	_includes := make(map[string]*parser.Thrift, len(includes))
   177  	for k, v := range includes {
   178  		t, err := parser.ParseString(k, v)
   179  		if err != nil {
   180  			return nil, err
   181  		}
   182  		_includes[k] = t
   183  	}
   184  
   185  	done := map[string]*parser.Thrift{path: tree}
   186  	if err := refIncludes(tree, path, done, _includes, isAbsIncludePath); err != nil {
   187  		return nil, err
   188  	}
   189  	return tree, nil
   190  }
   191  
   192  func refIncludes(tree *parser.Thrift, path string, done map[string]*parser.Thrift, includes map[string]*parser.Thrift, isAbsIncludePath bool) error {
   193  	done[path] = tree
   194  	for _, i := range tree.Includes {
   195  		p := i.Path
   196  		if isAbsIncludePath {
   197  			p = absPath(tree.Filename, i.Path)
   198  		}
   199  
   200  		// check cycle reference
   201  		if t := done[p]; t != nil {
   202  			i.Reference = t
   203  			continue
   204  		}
   205  
   206  		ref, ok := includes[p]
   207  		if !ok {
   208  			return fmt.Errorf("miss include path: %s for file: %s", p, tree.Filename)
   209  		}
   210  		if err := refIncludes(ref, p, done, includes, isAbsIncludePath); err != nil {
   211  			return err
   212  		}
   213  		i.Reference = ref
   214  	}
   215  	return nil
   216  }
   217  
   218  // Parse descriptor from parser.Thrift
   219  func parse(ctx context.Context, tree *parser.Thrift, mode meta.ParseServiceMode, opts Options, methods ...string) (*ServiceDescriptor, error) {
   220  	if len(tree.Services) == 0 {
   221  		return nil, errors.New("empty serverce from idls")
   222  	}
   223  	if err := semantic.ResolveSymbols(tree); err != nil {
   224  		return nil, err
   225  	}
   226  
   227  	sDsc := &ServiceDescriptor{
   228  		functions:   map[string]*FunctionDescriptor{},
   229  		annotations: []parser.Annotation{},
   230  	}
   231  
   232  	structsCache := compilingCache{}
   233  
   234  	// support one service
   235  	svcs := tree.Services
   236  	switch mode {
   237  	case meta.LastServiceOnly:
   238  		svcs = svcs[len(svcs)-1:]
   239  		sDsc.name = svcs[len(svcs)-1].Name
   240  	case meta.FirstServiceOnly:
   241  		svcs = svcs[:1]
   242  		sDsc.name = svcs[0].Name
   243  	case meta.CombineServices:
   244  		sDsc.name = "CombinedServices"
   245  	}
   246  
   247  	for _, svc := range svcs {
   248  		sopts := opts
   249  		// pass origin annotations
   250  		sDsc.annotations = copyAnnotationValues(svc.Annotations)
   251  		// handle thrid-party annotations
   252  		anns, _, next, err := mapAnnotations(ctx, svc.Annotations, AnnoScopeService, svc, sopts)
   253  		if err != nil {
   254  			return nil, err
   255  		}
   256  		for _, p := range anns {
   257  			if err := handleAnnotation(ctx, AnnoScopeService, p.inter, p.cont, &sopts, svcs); err != nil {
   258  				return nil, err
   259  			}
   260  		}
   261  
   262  		funcs := make([]funcTreePair, 0, len(svc.Functions))
   263  		getAllFuncs(svc, tree, &funcs)
   264  		if len(methods) > 0 {
   265  			funcs = findFuncs(funcs, methods)
   266  		}
   267  		for _, p := range funcs {
   268  			injectAnnotations((*[]*parser.Annotation)(&p.fn.Annotations), next)
   269  			if err := addFunction(ctx, p.fn, p.tree, sDsc, structsCache, sopts); err != nil {
   270  				return nil, err
   271  			}
   272  		}
   273  
   274  	}
   275  	return sDsc, nil
   276  }
   277  
   278  type funcTreePair struct {
   279  	tree *parser.Thrift
   280  	fn   *parser.Function
   281  }
   282  
   283  func findFuncs(funcs []funcTreePair, methods []string) (ret []funcTreePair) {
   284  	for _, m := range methods {
   285  		for _, p := range funcs {
   286  			if p.fn.Name == m {
   287  				ret = append(ret, p)
   288  			}
   289  		}
   290  	}
   291  	return
   292  }
   293  
   294  func getAllFuncs(svc *parser.Service, tree *parser.Thrift, ret *[]funcTreePair) {
   295  	funcs := *ret
   296  	n := len(svc.Functions)
   297  	l := len(funcs)
   298  	if cap(funcs) < l+n {
   299  		tmp := make([]funcTreePair, l, l+n)
   300  		copy(tmp, funcs)
   301  		funcs = tmp
   302  	}
   303  
   304  	for _, fn := range svc.Functions {
   305  		funcs = append(funcs, funcTreePair{
   306  			tree: tree,
   307  			fn:   fn,
   308  		})
   309  	}
   310  
   311  	if svc.Extends != "" {
   312  		ref := svc.GetReference()
   313  		if ref != nil {
   314  			idx := ref.GetIndex()
   315  			name := ref.GetName()
   316  			subTree := tree.Includes[idx].Reference
   317  			sub, _ := subTree.GetService(name)
   318  			if sub != nil {
   319  				getAllFuncs(sub, subTree, &funcs)
   320  			}
   321  		}
   322  	}
   323  	*ret = funcs
   324  	return
   325  }
   326  
   327  func addFunction(ctx context.Context, fn *parser.Function, tree *parser.Thrift, sDsc *ServiceDescriptor, structsCache compilingCache, opts Options) error {
   328  	// for fuzzing test
   329  	if opts.ParseFieldRandomRate > 0 {
   330  		rand.Seed(time.Now().UnixNano())
   331  	}
   332  
   333  	if sDsc.functions[fn.Name] != nil {
   334  		return fmt.Errorf("duplicate method name: %s", fn.Name)
   335  	}
   336  	if len(fn.Arguments) == 0 {
   337  		return fmt.Errorf("empty arguments in function: %s", fn.Name)
   338  	}
   339  
   340  	// find all endpoints of this function
   341  	enpdoints := []http.Endpoint{}
   342  	// for http router
   343  	for _, val := range fn.Annotations {
   344  		method := http.AnnoToMethod(val.Key)
   345  		if method != "" && len(val.Values) != 0 {
   346  			// record the pair{method,path}
   347  			enpdoints = append(enpdoints, http.Endpoint{Method: method, Path: val.Values[0]})
   348  		}
   349  	}
   350  
   351  	annos := copyAnnotationValues(fn.Annotations)
   352  	// handle thrid-party annotations
   353  	anns, _, nextAnns, err := mapAnnotations(ctx, fn.Annotations, AnnoScopeFunction, fn, opts)
   354  	if err != nil {
   355  		return err
   356  	}
   357  	for _, p := range anns {
   358  		// handle thrid-party annotations
   359  		if err := handleAnnotation(ctx, AnnoScopeFunction, p.inter, p.cont, &opts, fn); err != nil {
   360  			return err
   361  		}
   362  
   363  	}
   364  
   365  	var hasRequestBase bool
   366  	var req *TypeDescriptor
   367  	var resp *TypeDescriptor
   368  
   369  	// parse request field
   370  	if opts.ParseFunctionMode != meta.ParseResponseOnly {
   371  		// WARN: only support single argument
   372  		reqAst := fn.Arguments[0]
   373  		req = &TypeDescriptor{
   374  			typ: STRUCT,
   375  			struc: &StructDescriptor{
   376  				baseID:   FieldID(math.MaxUint16),
   377  				ids:      FieldIDMap{},
   378  				names:    FieldNameMap{},
   379  				requires: make(RequiresBitmap, 1),
   380  			},
   381  		}
   382  
   383  		reqType, err := parseType(ctx, reqAst.Type, tree, structsCache, 0, opts, nextAnns, Request)
   384  		if err != nil {
   385  			return err
   386  		}
   387  		if reqType.Type() == STRUCT {
   388  			for _, f := range reqType.Struct().names.all {
   389  				x := (*FieldDescriptor)(f.Val)
   390  				if x.isRequestBase {
   391  					hasRequestBase = true
   392  					break
   393  				}
   394  			}
   395  		}
   396  		reqField := &FieldDescriptor{
   397  			name: reqAst.Name,
   398  			id:   FieldID(reqAst.ID),
   399  			typ:  reqType,
   400  		}
   401  		req.Struct().ids.Set(FieldID(reqAst.ID), reqField)
   402  		req.Struct().names.Set(reqAst.Name, reqField)
   403  		req.Struct().names.Build()
   404  	}
   405  
   406  	// parse response filed
   407  	if opts.ParseFunctionMode != meta.ParseRequestOnly {
   408  		respAst := fn.FunctionType
   409  		resp = &TypeDescriptor{
   410  			typ: STRUCT,
   411  			struc: &StructDescriptor{
   412  				baseID:   FieldID(math.MaxUint16),
   413  				ids:      FieldIDMap{},
   414  				names:    FieldNameMap{},
   415  				requires: make(RequiresBitmap, 1),
   416  			},
   417  		}
   418  		respType, err := parseType(ctx, respAst, tree, structsCache, 0, opts, nextAnns, Response)
   419  		if err != nil {
   420  			return err
   421  		}
   422  		respField := &FieldDescriptor{
   423  			typ: respType,
   424  		}
   425  		resp.Struct().ids.Set(0, respField)
   426  		// response has no name or id
   427  		resp.Struct().names.Set("", respField)
   428  
   429  		// parse exceptions
   430  		if len(fn.Throws) > 0 {
   431  			// only support single exception
   432  			exp := fn.Throws[0]
   433  			exceptionType, err := parseType(ctx, exp.Type, tree, structsCache, 0, opts, nextAnns, Exception)
   434  			if err != nil {
   435  				return err
   436  			}
   437  			exceptionField := &FieldDescriptor{
   438  				name:  exp.Name,
   439  				alias: exp.Name,
   440  				id:    FieldID(exp.ID),
   441  				// isException: true,
   442  				typ: exceptionType,
   443  			}
   444  			resp.Struct().ids.Set(FieldID(exp.ID), exceptionField)
   445  			resp.Struct().names.Set(exp.Name, exceptionField)
   446  		}
   447  		resp.Struct().names.Build()
   448  	}
   449  
   450  	fnDsc := &FunctionDescriptor{
   451  		name:           fn.Name,
   452  		oneway:         fn.Oneway,
   453  		request:        req,
   454  		response:       resp,
   455  		hasRequestBase: hasRequestBase,
   456  		endpoints:      enpdoints,
   457  		annotations:    annos,
   458  	}
   459  	sDsc.functions[fn.Name] = fnDsc
   460  	return nil
   461  }
   462  
   463  // reuse builtin types
   464  var builtinTypes = map[string]*TypeDescriptor{
   465  	"void":   {name: "void", typ: VOID, struc: new(StructDescriptor)},
   466  	"bool":   {name: "bool", typ: BOOL},
   467  	"byte":   {name: "byte", typ: BYTE},
   468  	"i8":     {name: "i8", typ: I08},
   469  	"i16":    {name: "i16", typ: I16},
   470  	"i32":    {name: "i32", typ: I32},
   471  	"i64":    {name: "i64", typ: I64},
   472  	"double": {name: "double", typ: DOUBLE},
   473  	"string": {name: "string", typ: STRING},
   474  	"binary": {name: "binary", typ: STRING},
   475  }
   476  
   477  type compilingInstance struct {
   478  	desc        *TypeDescriptor
   479  	opts        Options
   480  	parseTarget ParseTarget
   481  }
   482  
   483  type compilingCache map[string]*compilingInstance
   484  
   485  // arg cache:
   486  // only support self reference on the same file
   487  // cross file self reference complicate matters
   488  func parseType(ctx context.Context, t *parser.Type, tree *parser.Thrift, cache compilingCache, recursionDepth int, opts Options, nextAnns []parser.Annotation, parseTarget ParseTarget) (*TypeDescriptor, error) {
   489  	if ty, ok := builtinTypes[t.Name]; ok {
   490  		return ty, nil
   491  	}
   492  
   493  	nextRecursionDepth := recursionDepth + 1
   494  
   495  	var err error
   496  	switch t.Name {
   497  	case "list":
   498  		ty := &TypeDescriptor{name: t.Name}
   499  		ty.typ = LIST
   500  		ty.elem, err = parseType(ctx, t.ValueType, tree, cache, nextRecursionDepth, opts, nextAnns, parseTarget)
   501  		return ty, err
   502  	case "set":
   503  		ty := &TypeDescriptor{name: t.Name}
   504  		ty.typ = SET
   505  		ty.elem, err = parseType(ctx, t.ValueType, tree, cache, nextRecursionDepth, opts, nextAnns, parseTarget)
   506  		return ty, err
   507  	case "map":
   508  		ty := &TypeDescriptor{name: t.Name}
   509  		ty.typ = MAP
   510  		if ty.key, err = parseType(ctx, t.KeyType, tree, cache, nextRecursionDepth, opts, nextAnns, parseTarget); err != nil {
   511  			return nil, err
   512  		}
   513  		ty.elem, err = parseType(ctx, t.ValueType, tree, cache, nextRecursionDepth, opts, nextAnns, parseTarget)
   514  		return ty, err
   515  	default:
   516  		// check the cache
   517  		if ty, ok := cache[t.Name]; ok && ty.parseTarget == parseTarget {
   518  			return ty.desc, nil
   519  		}
   520  
   521  		// get type from AST tree
   522  		typePkg, typeName := util.SplitSubfix(t.Name)
   523  		if typePkg != "" {
   524  			ref, ok := tree.GetReference(typePkg)
   525  			if !ok {
   526  				return nil, fmt.Errorf("miss reference: %s", typePkg)
   527  			}
   528  			tree = ref
   529  			// cross file reference need empty cache
   530  			cache = compilingCache{}
   531  		}
   532  		if typDef, ok := tree.GetTypedef(typeName); ok {
   533  			return parseType(ctx, typDef.Type, tree, cache, nextRecursionDepth, opts, nextAnns, parseTarget)
   534  		}
   535  		if _, ok := tree.GetEnum(typeName); ok {
   536  			if opts.ParseEnumAsInt64 {
   537  				return builtinTypes["i64"], nil
   538  			}
   539  			return builtinTypes["i32"], nil
   540  		}
   541  
   542  		// handle STRUCT type
   543  		var st *parser.StructLike
   544  		var ok bool
   545  		st, ok = tree.GetUnion(typeName)
   546  		if !ok {
   547  			st, ok = tree.GetStruct(typeName)
   548  		}
   549  		if !ok {
   550  			st, ok = tree.GetException(typeName)
   551  		}
   552  		if !ok {
   553  			return nil, fmt.Errorf("missing type: %s", typeName)
   554  		}
   555  
   556  		// copy original annotations
   557  		oannos := copyAnnotationValues(st.Annotations)
   558  		if opts.PutNameSpaceToAnnotation {
   559  			oannos = append(oannos, extractNameSpaceToAnnos(tree))
   560  		}
   561  
   562  		// inject previous annotations
   563  		injectAnnotations((*[]*parser.Annotation)(&st.Annotations), nextAnns)
   564  
   565  		// make struct descriptor
   566  		ty := &TypeDescriptor{
   567  			name: t.Name,
   568  			typ:  STRUCT,
   569  			struc: &StructDescriptor{
   570  				baseID:      FieldID(math.MaxUint16),
   571  				name:        typeName,
   572  				ids:         FieldIDMap{},
   573  				names:       FieldNameMap{},
   574  				requires:    make(RequiresBitmap, len(st.Fields)),
   575  				annotations: oannos,
   576  			},
   577  		}
   578  
   579  		if recursionDepth == 0 {
   580  			ctx = context.WithValue(ctx, CtxKeyIsBodyRoot, true)
   581  		} else {
   582  			ctx = context.WithValue(ctx, CtxKeyIsBodyRoot, false)
   583  		}
   584  
   585  		// handle thrid-party annotations for struct itself
   586  		anns, _, nextAnns2, err := mapAnnotations(ctx, st.Annotations, AnnoScopeStruct, st, opts)
   587  		if err != nil {
   588  			return nil, err
   589  		}
   590  		for _, p := range anns {
   591  			if err := handleAnnotation(ctx, AnnoScopeStruct, p.inter, p.cont, &opts, st); err != nil {
   592  				return nil, err
   593  			}
   594  		}
   595  		if st := ty.Struct(); st != nil {
   596  			cache[t.Name] = &compilingInstance{parseTarget: parseTarget, desc: ty}
   597  		}
   598  
   599  		// parse fields
   600  		for _, field := range st.Fields {
   601  			// fork field-specific options
   602  			fopts := opts
   603  			if fopts.ParseFieldRandomRate > 0 && rand.Float64() > fopts.ParseFieldRandomRate {
   604  				continue
   605  			}
   606  			var isRequestBase, isResponseBase bool
   607  			if fopts.EnableThriftBase {
   608  				isRequestBase = field.Type.Name == "base.Base" && recursionDepth == 0
   609  				isResponseBase = field.Type.Name == "base.BaseResp" && recursionDepth == 0
   610  			}
   611  			// cannot cache the request base
   612  			if isRequestBase {
   613  				delete(cache, t.Name)
   614  			}
   615  			if isRequestBase || isResponseBase {
   616  				ty.struc.baseID = FieldID(field.ID)
   617  			}
   618  			_f := &FieldDescriptor{
   619  				isRequestBase:  isRequestBase,
   620  				isResponseBase: isResponseBase,
   621  				id:             FieldID(field.ID),
   622  				name:           field.Name,
   623  				alias:          field.Name,
   624  				annotations:    copyAnnotationValues(field.Annotations),
   625  			}
   626  
   627  			// inject previous annotations
   628  			injectAnnotations((*[]*parser.Annotation)(&field.Annotations), nextAnns2)
   629  			anns, left, _, err := mapAnnotations(ctx, field.Annotations, AnnoScopeField, field, fopts)
   630  			if err != nil {
   631  				return nil, err
   632  			}
   633  
   634  			// handle annotations
   635  			ignore := false
   636  			for _, val := range left {
   637  				skip, err := handleNativeFieldAnnotation(val, _f, parseTarget)
   638  				if err != nil {
   639  					return nil, err
   640  				}
   641  				if skip {
   642  					ignore = true
   643  					break
   644  				}
   645  			}
   646  			if ignore {
   647  				continue
   648  			}
   649  			for _, p := range anns {
   650  				if err := handleFieldAnnotation(ctx, p.inter, p.cont, &fopts, _f, ty.struc, field); err != nil {
   651  					return nil, err
   652  				}
   653  			}
   654  			// copyAnnos(_f.annotations, anns)
   655  
   656  			// recursively parse field type
   657  			// WARN: options and annotations on field SHOULD NOT override these on their type definition
   658  			if _f.typ, err = parseType(ctx, field.Type, tree, cache, nextRecursionDepth, opts, nil, parseTarget); err != nil {
   659  				return nil, err
   660  			}
   661  
   662  			// make default value
   663  			// WARN: ignore errors here
   664  			if fopts.UseDefaultValue {
   665  				dv, _ := makeDefaultValue(_f.typ, field.Default, tree)
   666  				_f.defaultValue = dv
   667  			}
   668  			// set field id
   669  			ty.Struct().ids.Set(FieldID(field.ID), _f)
   670  			// set field requireness
   671  			convertRequireness(field.Requiredness, ty.struc, _f, fopts)
   672  			// set field key
   673  			if fopts.MapFieldWay == meta.MapFieldUseAlias {
   674  				ty.Struct().names.Set(_f.alias, _f)
   675  			} else if fopts.MapFieldWay == meta.MapFieldUseFieldName {
   676  				ty.Struct().names.Set(_f.name, _f)
   677  			} else {
   678  				ty.Struct().names.Set(_f.alias, _f)
   679  				ty.Struct().names.Set(_f.name, _f)
   680  			}
   681  
   682  		}
   683  		// buidl field name map
   684  		ty.Struct().names.Build()
   685  		return ty, nil
   686  	}
   687  }
   688  
   689  func convertRequireness(r parser.FieldType, st *StructDescriptor, f *FieldDescriptor, opts Options) {
   690  	var req Requireness
   691  	switch r {
   692  	case parser.FieldType_Default:
   693  		f.required = DefaultRequireness
   694  		if opts.SetOptionalBitmap {
   695  			req = RequiredRequireness
   696  		} else {
   697  			req = DefaultRequireness
   698  		}
   699  	case parser.FieldType_Optional:
   700  		f.required = OptionalRequireness
   701  		if opts.SetOptionalBitmap {
   702  			req = DefaultRequireness
   703  		} else {
   704  			req = OptionalRequireness
   705  		}
   706  	case parser.FieldType_Required:
   707  		f.required = RequiredRequireness
   708  		req = RequiredRequireness
   709  	default:
   710  		panic("invalid requireness type")
   711  	}
   712  
   713  	if f.isRequestBase || f.isResponseBase {
   714  		// hence users who set EnableThriftBase can pass thrift base through conversion context, the field is always set optional
   715  		req = OptionalRequireness
   716  	}
   717  
   718  	st.requires.Set(f.id, req)
   719  }
   720  
   721  func assertType(expected, but Type) error {
   722  	if expected == but {
   723  		return nil
   724  	}
   725  	return fmt.Errorf("need %s type, but got: %s", expected, but)
   726  }
   727  
   728  func makeDefaultValue(typ *TypeDescriptor, val *parser.ConstValue, tree *parser.Thrift) (*DefaultValue, error) {
   729  	if val == nil {
   730  		return nil, nil
   731  	}
   732  	switch val.Type {
   733  	case parser.ConstType_ConstInt:
   734  		if !typ.typ.IsInt() {
   735  			return nil, fmt.Errorf("mismatched int default value with type %s", typ.name)
   736  		}
   737  		if x := val.TypedValue.Int; x != nil {
   738  			v := int64(*x)
   739  			p := BinaryProtocol{Buf: make([]byte, 0, 4)}
   740  			p.WriteInt(typ.typ, int(v))
   741  			jbuf := json.EncodeInt64(make([]byte, 0, 8), v)
   742  			return &DefaultValue{
   743  				goValue:      v,
   744  				jsonValue:    rt.Mem2Str(jbuf),
   745  				thriftBinary: rt.Mem2Str(p.Buf),
   746  			}, nil
   747  		}
   748  	case parser.ConstType_ConstDouble:
   749  		if typ.typ != DOUBLE {
   750  			return nil, fmt.Errorf("mismatched double default value with type %s", typ.name)
   751  		}
   752  		if x := val.TypedValue.Double; x != nil {
   753  			v := float64(*x)
   754  			tbuf := make([]byte, 8)
   755  			BinaryEncoding{}.EncodeDouble(tbuf, v)
   756  			jbuf := json.EncodeFloat64(make([]byte, 0, 8), v)
   757  			return &DefaultValue{
   758  				goValue:      v,
   759  				jsonValue:    rt.Mem2Str(jbuf),
   760  				thriftBinary: rt.Mem2Str(tbuf),
   761  			}, nil
   762  		}
   763  	case parser.ConstType_ConstLiteral:
   764  		if typ.typ != STRING {
   765  			return nil, fmt.Errorf("mismatched string default value with type %s", typ.name)
   766  		}
   767  		if x := val.TypedValue.Literal; x != nil {
   768  			v := string(*x)
   769  			tbuf := make([]byte, len(v)+4)
   770  			BinaryEncoding{}.EncodeString(tbuf, v)
   771  			jbuf := json.EncodeString(make([]byte, 0, len(v)+2), v)
   772  			return &DefaultValue{
   773  				goValue:      v,
   774  				jsonValue:    rt.Mem2Str(jbuf),
   775  				thriftBinary: rt.Mem2Str(tbuf),
   776  			}, nil
   777  		}
   778  	case parser.ConstType_ConstIdentifier:
   779  		x := *val.TypedValue.Identifier
   780  
   781  		// try to handle it as bool
   782  		if typ.typ == BOOL {
   783  			if v := strings.ToLower(x); v == "true" {
   784  				return &DefaultValue{
   785  					goValue:      true,
   786  					jsonValue:    "true",
   787  					thriftBinary: string([]byte{0x01}),
   788  				}, nil
   789  			} else if v == "false" {
   790  				return &DefaultValue{
   791  					goValue:      false,
   792  					jsonValue:    "false",
   793  					thriftBinary: string([]byte{0x00}),
   794  				}, nil
   795  			}
   796  		}
   797  
   798  		// try to handle as const value
   799  		var ctree = tree
   800  		pkg, name := util.SplitSubfix(x)
   801  		if pkg != "" {
   802  			if nt, ok := tree.GetReference(pkg); ok && nt != nil {
   803  				ctree = nt
   804  			}
   805  		}
   806  		y, ok := ctree.GetConstant(name)
   807  		if ok && y != nil {
   808  			return makeDefaultValue(typ, y.Value, ctree)
   809  		}
   810  
   811  		// try to handle as enum value
   812  		if pkg == "" {
   813  			return nil, fmt.Errorf("not found identifier: %s", x)
   814  		}
   815  		emv := name
   816  		emp, emt := util.SplitSubfix(pkg)
   817  		if emp != "" {
   818  			if nt, ok := tree.GetReference(emp); ok && nt != nil {
   819  				tree = nt
   820  			}
   821  		}
   822  		z, ok := tree.GetEnum(emt)
   823  		if !ok || z == nil {
   824  			return nil, fmt.Errorf("not found enum type: %s", emt)
   825  		}
   826  		if !typ.typ.IsInt() {
   827  			return nil, fmt.Errorf("mismatched int default value with type %s", typ.name)
   828  		}
   829  		for _, vv := range z.Values {
   830  			if vv.Name == emv {
   831  				v := int64(vv.Value)
   832  				p := BinaryProtocol{Buf: make([]byte, 0, 4)}
   833  				p.WriteInt(typ.typ, int(v))
   834  				jbuf := json.EncodeInt64(make([]byte, 0, 8), v)
   835  				return &DefaultValue{
   836  					goValue:      v,
   837  					jsonValue:    rt.Mem2Str(jbuf),
   838  					thriftBinary: rt.Mem2Str(p.Buf),
   839  				}, nil
   840  			}
   841  		}
   842  
   843  	}
   844  	return nil, nil
   845  }