github.com/cloudwego/kitex@v0.9.0/tool/internal_pkg/pluginmode/thriftgo/struct_tpl.go (about)

     1  // Copyright 2021 CloudWeGo Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //   http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package thriftgo
    16  
    17  const structLikeCodec = `
    18  {{define "StructLikeCodec"}}
    19  {{if GenerateFastAPIs}}
    20  {{template "StructLikeFastRead" .}}
    21  
    22  {{template "StructLikeFastReadField" .}}
    23  
    24  {{template "StructLikeFastWrite" .}}
    25  
    26  {{template "StructLikeFastWriteNocopy" .}}
    27  
    28  {{template "StructLikeLength" .}}
    29  
    30  {{template "StructLikeFastWriteField" .}}
    31  
    32  {{template "StructLikeFieldLength" .}}
    33  {{- end}}{{/* if GenerateFastAPIs */}}
    34  
    35  {{if GenerateDeepCopyAPIs}}
    36  {{template "StructLikeDeepCopy" .}}
    37  {{- end}}{{/* if GenerateDeepCopyAPIs */}}
    38  {{- end}}{{/* define "StructLikeCodec" */}}
    39  `
    40  
    41  const structLikeFastRead = `
    42  {{define "StructLikeFastRead"}}
    43  {{- $TypeName := .GoName}}
    44  func (p *{{$TypeName}}) FastRead(buf []byte) (int, error) {
    45  	var err error
    46  	var offset int
    47  	var l int
    48  	var fieldTypeId thrift.TType
    49  	var fieldId int16
    50  	{{- range .Fields}}
    51  	{{- if .Requiredness.IsRequired}}
    52  	var isset{{.GoName}} bool = false
    53  	{{- end}}
    54  	{{- end}}
    55  	_, l, err = bthrift.Binary.ReadStructBegin(buf)
    56  	offset += l
    57  	if err != nil {
    58  		goto ReadStructBeginError
    59  	}
    60  
    61  	for {
    62  		{{- if Features.KeepUnknownFields}}
    63  		{{- if gt (len .Fields) 0}}
    64  		var isUnknownField bool
    65  		{{- end}}
    66  		var beginOff int = offset
    67  		{{- end}}
    68  		_, fieldTypeId, fieldId, l, err = bthrift.Binary.ReadFieldBegin(buf[offset:])
    69  		offset += l
    70  		if err != nil {
    71  			goto ReadFieldBeginError
    72  		}
    73  		if fieldTypeId == thrift.STOP {
    74  			break;
    75  		}
    76  		{{if gt (len .Fields) 0 -}}
    77  		switch fieldId {
    78  		{{- range .Fields}}
    79  		case {{.ID}}:
    80  			if fieldTypeId == thrift.{{.Type | GetTypeIDConstant }} {
    81  				l, err = p.FastReadField{{Str .ID}}(buf[offset:])
    82  				offset += l
    83  				if err != nil {
    84  					goto ReadFieldError
    85  				}
    86  				{{- if .Requiredness.IsRequired}}
    87  				isset{{.GoName}} = true
    88  				{{- end}}
    89  			} else {
    90  				l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId)
    91  				offset += l
    92  				if err != nil {
    93  					goto SkipFieldError
    94  				}
    95  			}
    96  		{{- end}}{{/* range .Fields */}}
    97  		default:
    98  			l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId)
    99  			offset += l
   100  			if err != nil {
   101  				goto SkipFieldError
   102  			}
   103  			{{- if Features.KeepUnknownFields}}
   104  			isUnknownField = true
   105  			{{- end}}{{/* if Features.KeepUnknownFields */}}
   106  		}
   107  		{{- else -}}
   108  		l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId)
   109  		offset += l
   110  		if err != nil {
   111  			goto SkipFieldError
   112  		}
   113  		{{- end}}{{/* if len(.Fields) > 0 */}}
   114  
   115  		l, err = bthrift.Binary.ReadFieldEnd(buf[offset:])
   116  		offset += l
   117  		if err != nil {
   118  		  goto ReadFieldEndError
   119  		}
   120  
   121  		{{- if Features.KeepUnknownFields}}
   122  		{{if gt (len .Fields) 0 -}}
   123  		if isUnknownField {
   124  			p._unknownFields = append(p._unknownFields, buf[beginOff:offset]...)
   125  		}
   126  		{{- else -}}
   127  		p._unknownFields = append(p._unknownFields, buf[beginOff:offset]...)
   128  		{{- end}}
   129  		{{- end}}{{/* if Features.KeepUnknownFields */}}
   130  	}
   131  	l, err = bthrift.Binary.ReadStructEnd(buf[offset:])
   132  	offset += l
   133  	if err != nil {
   134  		goto ReadStructEndError
   135  	}
   136  	{{ $NeedRequiredFieldNotSetError := false }}
   137  	{{- range .Fields}}
   138  	{{- if .Requiredness.IsRequired}}
   139  	{{ $NeedRequiredFieldNotSetError = true }}
   140  	if !isset{{.GoName}} {
   141  		fieldId = {{.ID}}
   142  		goto RequiredFieldNotSetError
   143  	}
   144  	{{- end}}
   145  	{{- end}}
   146  	return offset, nil
   147  ReadStructBeginError:
   148  	return offset, thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err)
   149  ReadFieldBeginError:
   150  	return offset, thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err)
   151  {{- if gt (len .Fields) 0}}
   152  ReadFieldError:
   153  	return offset, thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_{{$TypeName}}[fieldId]), err)
   154  {{- end}}
   155  SkipFieldError:
   156  	return offset, thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err)
   157  ReadFieldEndError:
   158  	return offset, thrift.PrependError(fmt.Sprintf("%T read field end error", p), err)
   159  ReadStructEndError:
   160  	return offset, thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
   161  {{- if $NeedRequiredFieldNotSetError }}
   162  RequiredFieldNotSetError:
   163  	return offset, thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("required field %s is not set", fieldIDToName_{{$TypeName}}[fieldId]))
   164  {{- end}}{{/* if $NeedRequiredFieldNotSetError */}}
   165  }
   166  {{- end}}{{/* define "StructLikeFastRead" */}}
   167  `
   168  
   169  const structLikeFastReadField = `
   170  {{define "StructLikeFastReadField"}}
   171  {{- $TypeName := .GoName}}
   172  {{- range .Fields}}
   173  {{$FieldName := .GoName}}
   174  func (p *{{$TypeName}}) FastReadField{{Str .ID}}(buf []byte) (int, error) {
   175  	offset := 0
   176  	{{- $ctx := MkRWCtx .}}
   177  	{{ template "FieldFastRead" $ctx}}
   178  	return offset, nil
   179  }
   180  {{- end}}{{/* range .Fields */}}
   181  {{- end}}{{/* define "StructLikeFastReadField" */}}
   182  `
   183  
   184  // TODO: check required
   185  const structLikeDeepCopy = `
   186  {{define "StructLikeDeepCopy"}}
   187  {{- $TypeName := .GoName}}
   188  func (p *{{$TypeName}}) DeepCopy(s interface{}) error {
   189  	{{if gt (len .Fields) 0 -}}
   190  	src, ok := s.(*{{$TypeName}})
   191  	if !ok {
   192  		return fmt.Errorf("%T's type not matched %T", s, p)
   193  	}
   194  	{{- end -}}
   195  	{{- range .Fields}}
   196  	{{- $ctx := MkRWCtx .}}
   197  	{{ template "FieldDeepCopy" $ctx}}
   198  	{{- end}}{{/* range .Fields */}}
   199  	{{/* line break */}}
   200  	return nil
   201  }
   202  {{- end}}{{/* define "StructLikeDeepCopy" */}}
   203  `
   204  
   205  const structLikeFastWrite = `
   206  {{define "StructLikeFastWrite"}}
   207  {{- $TypeName := .GoName}}
   208  // for compatibility
   209  func (p *{{$TypeName}}) FastWrite(buf []byte) int {
   210  	return 0
   211  }
   212  {{- end}}{{/* define "StructLikeFastWrite" */}}
   213  `
   214  
   215  const structLikeFastWriteNocopy = `
   216  {{define "StructLikeFastWriteNocopy"}}
   217  {{- $TypeName := .GoName}}
   218  func (p *{{$TypeName}}) FastWriteNocopy(buf []byte, binaryWriter bthrift.BinaryWriter) int {
   219  	offset := 0
   220  	{{- if eq .Category "union"}}
   221  	var c int
   222  	if p != nil {
   223  		if c = p.CountSetFields{{$TypeName}}(); c != 1 {
   224  			goto CountSetFieldsError
   225  		}
   226  	}
   227  	{{- end}}
   228  	offset += bthrift.Binary.WriteStructBegin(buf[offset:], "{{.Name}}")
   229  	if p != nil {
   230  		{{- $reorderedFields := ReorderStructFields .Fields}}
   231  		{{- range $reorderedFields}}
   232  		offset += p.fastWriteField{{Str .ID}}(buf[offset:], binaryWriter)
   233  		{{- end}}
   234  		{{- if Features.KeepUnknownFields}}
   235  		offset += copy(buf[offset:], p._unknownFields)
   236  		{{- end}}{{/* if Features.KeepUnknownFields */}}
   237  	}
   238  	offset += bthrift.Binary.WriteFieldStop(buf[offset:])
   239  	offset += bthrift.Binary.WriteStructEnd(buf[offset:])
   240  	return offset
   241  {{- if eq .Category "union"}}
   242  CountSetFieldsError:
   243  	panic(fmt.Errorf("%T write union: exactly one field must be set (%d set).", p, c))
   244  {{- end}}
   245  }
   246  {{- end}}{{/* define "StructLikeFastWriteNocopy" */}}
   247  `
   248  
   249  const structLikeLength = `
   250  {{define "StructLikeLength"}}
   251  {{- $TypeName := .GoName}}
   252  func (p *{{$TypeName}}) BLength() int {
   253  	l := 0
   254  	{{- if eq .Category "union"}}
   255  	var c int
   256  	if p != nil {
   257  		if c = p.CountSetFields{{$TypeName}}(); c != 1 {
   258  			goto CountSetFieldsError
   259  		}
   260  	}
   261  	{{- end}}
   262  	l += bthrift.Binary.StructBeginLength("{{.Name}}")
   263  	if p != nil {
   264  		{{- range .Fields}}
   265  		l += p.field{{Str .ID}}Length()
   266  		{{- end}}
   267  		{{- if Features.KeepUnknownFields}}
   268  		l += len(p._unknownFields)
   269  		{{- end}}{{/* if Features.KeepUnknownFields */}}
   270  	}
   271  	l += bthrift.Binary.FieldStopLength()
   272  	l += bthrift.Binary.StructEndLength()
   273  	return l
   274  {{- if eq .Category "union"}}
   275  CountSetFieldsError:
   276  	panic(fmt.Errorf("%T write union: exactly one field must be set (%d set).", p, c))
   277  {{- end}}
   278  }
   279  {{- end}}{{/* define "StructLikeLength" */}}
   280  `
   281  
   282  const structLikeFastWriteField = `
   283  {{define "StructLikeFastWriteField"}}
   284  {{- $TypeName := .GoName}}
   285  {{- range .Fields}}
   286  {{- $FieldName := .GoName}}
   287  {{- $TypeID := .Type | GetTypeIDConstant }}
   288  func (p *{{$TypeName}}) fastWriteField{{Str .ID}}(buf []byte, binaryWriter bthrift.BinaryWriter) int {
   289  	offset := 0
   290  	{{- if .Requiredness.IsOptional}}
   291  	if p.{{.IsSetter}}() {
   292  	{{- end}}
   293  	offset += bthrift.Binary.WriteFieldBegin(buf[offset:], "{{.Name}}", thrift.{{$TypeID}}, {{.ID}})
   294  	{{- $ctx := MkRWCtx .}}
   295  	{{- template "FieldFastWrite" $ctx}}
   296  	offset += bthrift.Binary.WriteFieldEnd(buf[offset:])
   297  	{{- if .Requiredness.IsOptional}}
   298  	}
   299  	{{- end}}
   300  	return offset
   301  }
   302  {{end}}{{/* range .Fields */}}
   303  {{- end}}{{/* define "StructLikeFastWriteField" */}}
   304  `
   305  
   306  const structLikeFieldLength = `
   307  {{define "StructLikeFieldLength"}}
   308  {{- $TypeName := .GoName}}
   309  {{- range .Fields}}
   310  {{- $FieldName := .GoName}}
   311  {{- $TypeID := .Type | GetTypeIDConstant }}
   312  func (p *{{$TypeName}}) field{{Str .ID}}Length() int {
   313  	l := 0
   314  	{{- if .Requiredness.IsOptional}}
   315  	if p.{{.IsSetter}}() {
   316  	{{- end}}
   317  	l += bthrift.Binary.FieldBeginLength("{{.Name}}", thrift.{{$TypeID}}, {{.ID}})
   318  	{{- $ctx := MkRWCtx .}}
   319  	{{- template "FieldLength" $ctx}}
   320  	l += bthrift.Binary.FieldEndLength()
   321  	{{- if .Requiredness.IsOptional}}
   322  	}
   323  	{{- end}}
   324  	return l
   325  }
   326  {{end}}{{/* range .Fields */}}
   327  {{- end}}{{/* define "StructLikeFieldLength" */}}
   328  `
   329  
   330  const fieldFastRead = `
   331  {{define "FieldFastRead"}}
   332  	{{- if .Type.Category.IsStructLike}}
   333  		{{- template "FieldFastReadStructLike" .}}
   334  	{{- else if .Type.Category.IsContainerType}}
   335  		{{- template "FieldFastReadContainer" .}}
   336  	{{- else}}{{/* IsBaseType */}}
   337  		{{- template "FieldFastReadBaseType" .}}
   338  	{{- end}}
   339  {{- end}}{{/* define "FieldFastRead" */}}
   340  `
   341  
   342  const fieldFastReadStructLike = `
   343  {{define "FieldFastReadStructLike"}}
   344  	{{- if .NeedDecl}}
   345  	{{- .Target}} := {{.TypeName.Deref.NewFunc}}()
   346  	{{- else}}
   347  	tmp := {{.TypeName.Deref.NewFunc}}()
   348  	{{- end}}
   349  	if l, err := {{- if .NeedDecl}}{{.Target}}{{else}}tmp{{end}}.FastRead(buf[offset:]); err != nil {
   350  		return offset, err
   351  	} else {
   352  		offset += l
   353  	}
   354  	{{if not .NeedDecl}}{{- .Target}} = tmp{{end}}
   355  {{- end}}{{/* define "FieldFastReadStructLike" */}} 
   356  `
   357  
   358  const fieldFastReadBaseType = `
   359  {{define "FieldFastReadBaseType"}}
   360  	{{- $DiffType := or .Type.Category.IsEnum .Type.Category.IsBinary}}
   361  	{{- if .NeedDecl}}
   362  	var {{.Target}} {{.TypeName}}
   363  	{{- end}}
   364  	if v, l, err := bthrift.Binary.Read{{.TypeID}}(buf[offset:]); err != nil {
   365  		return offset, err
   366  	} else {
   367  		offset += l
   368  	{{ if .IsPointer}}
   369  		{{- if $DiffType}}
   370  		tmp := {{.TypeName.Deref}}(v)
   371  		{{.Target}} = &tmp
   372  		{{- else -}}
   373  		{{.Target}} = &v
   374  		{{- end}}
   375  	{{ else}}
   376  		{{- if $DiffType}}
   377  		{{.Target}} = {{.TypeName}}(v)
   378  		{{- else}}
   379  		{{.Target}} = v
   380  		{{- end}}
   381  	{{ end}}
   382  	}
   383  {{- end}}{{/* define "FieldFastReadBaseType" */}}
   384  `
   385  
   386  const fieldFastReadContainer = `
   387  {{define "FieldFastReadContainer"}}
   388  	{{- if eq "Map" .TypeID}}
   389  	     {{- template "FieldFastReadMap" .}}
   390  	{{- else if eq "List" .TypeID}}
   391  	     {{- template "FieldFastReadList" .}}
   392  	{{- else}}
   393  	     {{- template "FieldFastReadSet" .}}
   394  	{{- end}}
   395  {{- end}}{{/* define "FieldFastReadContainer" */}}
   396  `
   397  
   398  const fieldFastReadMap = `
   399  {{define "FieldFastReadMap"}}
   400  	_, _, size, l, err := bthrift.Binary.ReadMapBegin(buf[offset:])
   401  	offset += l
   402  	if err != nil {
   403  		return offset, err
   404  	}
   405  	{{.Target}} {{if .NeedDecl}}:{{end}}= make({{.TypeName}}, size)
   406  	for i := 0; i < size; i++ {
   407  		{{- $key := .GenID "_key"}}
   408  		{{- $ctx := .KeyCtx.WithDecl.WithTarget $key}}
   409  		{{- template "FieldFastRead" $ctx}}
   410  		{{/* line break */}}
   411  		{{- $val := .GenID "_val"}}
   412  		{{- $ctx := .ValCtx.WithDecl.WithTarget $val}}
   413  		{{- template "FieldFastRead" $ctx}}
   414  
   415  		{{if and .ValCtx.Type.Category.IsStructLike Features.ValueTypeForSIC}}
   416  			{{$val = printf "*%s" $val}}
   417  		{{end}}
   418  
   419  		{{.Target}}[{{$key}}] = {{$val}}
   420  	}
   421  	if l, err := bthrift.Binary.ReadMapEnd(buf[offset:]); err != nil {
   422  		return offset, err
   423  	} else {
   424  		offset += l
   425  	}
   426  {{- end}}{{/* define "FieldFastReadMap" */}}
   427  `
   428  
   429  const fieldFastReadSet = `
   430  {{define "FieldFastReadSet"}}
   431  	_, size, l, err := bthrift.Binary.ReadSetBegin(buf[offset:])
   432  	offset += l
   433  	if err != nil {
   434  		return offset, err
   435  	}
   436  	{{.Target}} {{if .NeedDecl}}:{{end}}= make({{.TypeName}}, 0, size)
   437  	for i := 0; i < size; i++ {
   438  		{{- $val := .GenID "_elem"}}
   439  		{{- $ctx := .ValCtx.WithDecl.WithTarget $val}}
   440  		{{- template "FieldFastRead" $ctx}}
   441  
   442  		{{if and .ValCtx.Type.Category.IsStructLike Features.ValueTypeForSIC}}
   443  			{{$val = printf "*%s" $val}}
   444  		{{end}}
   445  
   446  		{{.Target}} = append({{.Target}}, {{$val}})
   447  	}
   448  	if l, err := bthrift.Binary.ReadSetEnd(buf[offset:]); err != nil {
   449  		return offset, err
   450  	} else {
   451  		offset += l
   452  	}
   453  {{- end}}{{/* define "FieldFastReadSet" */}}
   454  `
   455  
   456  const fieldFastReadList = `
   457  {{define "FieldFastReadList"}}
   458  	_, size, l, err := bthrift.Binary.ReadListBegin(buf[offset:])
   459  	offset += l
   460  	if err != nil {
   461  		return offset, err
   462  	}
   463  	{{.Target}} {{if .NeedDecl}}:{{end}}= make({{.TypeName}}, 0, size)
   464  	for i := 0; i < size; i++ {
   465  		{{- $val := .GenID "_elem"}}
   466  		{{- $ctx := .ValCtx.WithDecl.WithTarget $val}}
   467  		{{- template "FieldFastRead" $ctx}}
   468  
   469  		{{if and .ValCtx.Type.Category.IsStructLike Features.ValueTypeForSIC}}
   470  			{{$val = printf "*%s" $val}}
   471  		{{end}}
   472  
   473  		{{.Target}} = append({{.Target}}, {{$val}})
   474  	}
   475  	if l, err := bthrift.Binary.ReadListEnd(buf[offset:]); err != nil {
   476  		return offset, err
   477  	} else {
   478  		offset += l
   479  	}
   480  {{- end}}{{/* define "FieldFastReadList" */}}
   481  `
   482  
   483  const fieldDeepCopy = `
   484  {{define "FieldDeepCopy"}}
   485  	{{- if .Type.Category.IsStructLike}}
   486  		{{- template "FieldDeepCopyStructLike" .}}
   487  	{{- else if .Type.Category.IsContainerType}}
   488  		{{- template "FieldDeepCopyContainer" .}}
   489  	{{- else}}{{/* IsBaseType */}}
   490  		{{- template "FieldDeepCopyBaseType" .}}
   491  	{{- end}}
   492  {{- end}}{{/* define "FieldDeepCopy" */}}
   493  `
   494  
   495  const fieldDeepCopyStructLike = `
   496  {{define "FieldDeepCopyStructLike"}}
   497  {{- $Src := SourceTarget .Target}}
   498  	{{- if .NeedDecl}}
   499  	var {{.Target}} *{{.TypeName.Deref}}
   500  	{{- else}}
   501  	var _{{FieldName .Target}} *{{.TypeName.Deref}}
   502  	{{- end}}
   503  	if {{$Src}} != nil {
   504  		{{- if .NeedDecl}}{{.Target}}{{else}}_{{FieldName .Target}}{{end}} = &{{.TypeName.Deref}}{}
   505  		if err := {{- if .NeedDecl}}{{.Target}}{{else}}_{{FieldName .Target}}{{end}}.DeepCopy({{$Src}}); err != nil {
   506  			return err
   507  		}
   508  	}
   509  	{{if not .NeedDecl}}{{- .Target}} = _{{FieldName .Target}}{{end}}
   510  {{- end}}{{/* define "FieldDeepCopyStructLike" */}} 
   511  `
   512  
   513  const fieldDeepCopyContainer = `
   514  {{define "FieldDeepCopyContainer"}}
   515  	{{- if eq "Map" .TypeID}}
   516  	     {{- template "FieldDeepCopyMap" .}}
   517  	{{- else if eq "List" .TypeID}}
   518  	     {{- template "FieldDeepCopyList" .}}
   519  	{{- else}}
   520  	     {{- template "FieldDeepCopySet" .}}
   521  	{{- end}}
   522  {{- end}}{{/* define "FieldDeepCopyContainer" */}}
   523  `
   524  
   525  const fieldDeepCopyMap = `
   526  {{define "FieldDeepCopyMap"}}
   527  {{- $Src := SourceTarget .Target}}
   528  	{{- if .NeedDecl}}var {{.Target}} {{.TypeName}}{{- end}}
   529  	if {{$Src}} != nil {
   530  		{{.Target}} = make({{.TypeName}}, len({{$Src}}))
   531  		{{- $key := .GenID "_key"}}
   532  		{{- $val := .GenID "_val"}}
   533  		for {{SourceTarget $key}}, {{SourceTarget $val}} := range {{$Src}} {
   534  			{{- $ctx := .KeyCtx.WithDecl.WithTarget $key}}
   535  			{{- template "FieldDeepCopy" $ctx}}
   536  			{{/* line break */}}
   537  			{{- $ctx := .ValCtx.WithDecl.WithTarget $val}}
   538  			{{- template "FieldDeepCopy" $ctx}}
   539  
   540  			{{- if and .ValCtx.Type.Category.IsStructLike Features.ValueTypeForSIC}}
   541  				{{$val = printf "*%s" $val}}
   542  			{{- end}}
   543  
   544  			{{.Target}}[{{$key}}] = {{$val}}
   545  		}
   546  	}
   547  {{- end}}{{/* define "FieldDeepCopyMap" */}}
   548  `
   549  
   550  const fieldDeepCopyList = `
   551  {{define "FieldDeepCopyList"}}
   552  {{- $Src := SourceTarget .Target}}
   553  	{{if .NeedDecl}}var {{.Target}} {{.TypeName}}{{end}}
   554  	if {{$Src}} != nil {
   555  		{{.Target}} = make({{.TypeName}}, 0, len({{$Src}}))
   556  		{{- $val := .GenID "_elem"}}
   557  		for _, {{SourceTarget $val}} := range {{$Src}} {
   558  			{{- $ctx := .ValCtx.WithDecl.WithTarget $val}}
   559  			{{- template "FieldDeepCopy" $ctx}}
   560  
   561  			{{- if and .ValCtx.Type.Category.IsStructLike Features.ValueTypeForSIC}}
   562  				{{$val = printf "*%s" $val}}
   563  			{{- end}}
   564  
   565  			{{.Target}} = append({{.Target}}, {{$val}})
   566  		}
   567  	}
   568  {{- end}}{{/* define "FieldDeepCopyList" */}}
   569  `
   570  
   571  const fieldDeepCopySet = `
   572  {{define "FieldDeepCopySet"}}
   573  {{- $Src := SourceTarget .Target}}
   574  	{{if .NeedDecl}}var {{.Target}} {{.TypeName}}{{end}}
   575  	if {{$Src}} != nil {
   576  		{{.Target}} = make({{.TypeName}}, 0, len({{$Src}}))
   577  		{{- $val := .GenID "_elem"}}
   578  		for _, {{SourceTarget $val}} := range {{$Src}} {
   579  			{{- $ctx := .ValCtx.WithDecl.WithTarget $val}}
   580  			{{- template "FieldDeepCopy" $ctx}}
   581  
   582  			{{- if and .ValCtx.Type.Category.IsStructLike Features.ValueTypeForSIC}}
   583  				{{$val = printf "*%s" $val}}
   584  			{{- end}}
   585  
   586  			{{.Target}} = append({{.Target}}, {{$val}})
   587  		}
   588  	}
   589  {{- end}}{{/* define "FieldDeepCopySet" */}}
   590  `
   591  
   592  const fieldDeepCopyBaseType = `
   593  {{define "FieldDeepCopyBaseType"}}
   594  {{- $Src := SourceTarget .Target}}
   595  	{{- if .NeedDecl}}
   596  	var {{.Target}} {{.TypeName}}
   597  	{{- end}}
   598  	{{- if .IsPointer}}
   599  		if {{$Src}} != nil {
   600  			{{- if IsGoStringType .TypeName}}
   601  			if *{{$Src}} != "" {
   602  				tmp := kutils.StringDeepCopy(*{{$Src}})
   603  				{{.Target}} = &tmp
   604  			}
   605  			{{- else if .Type.Category.IsBinary}}
   606  			if len(*{{$Src}}) != 0 {
   607  				tmp := make([]byte, len(*{{$Src}}))
   608  				copy(tmp, *{{$Src}})
   609  				{{.Target}} = &tmp
   610  			}
   611  			{{- else}}
   612  			tmp := *{{$Src}}
   613  			{{.Target}} = &tmp
   614  			{{- end}}
   615  		}
   616  	{{- else}}
   617  		{{- if IsGoStringType .TypeName}}
   618  		if {{$Src}} != "" {
   619  			{{.Target}} = kutils.StringDeepCopy({{$Src}})
   620  		}
   621  		{{- else if .Type.Category.IsBinary}}
   622  		if len({{$Src}}) != 0 {
   623  			tmp := make([]byte, len({{$Src}}))
   624  			copy(tmp, {{$Src}})
   625  			{{.Target}} = tmp
   626  		}
   627  		{{- else}}
   628  		{{.Target}} = {{$Src}}
   629  		{{- end}}
   630  	{{- end}}
   631  {{- end}}{{/* define "FieldDeepCopyBaseType" */}}
   632  `
   633  
   634  const fieldFastWrite = `
   635  {{define "FieldFastWrite"}}
   636  	{{- if .Type.Category.IsStructLike}}
   637  		{{- template "FieldFastWriteStructLike" . -}}
   638  	{{- else if .Type.Category.IsContainerType}}
   639  		{{- template "FieldFastWriteContainer" . -}}
   640  	{{- else}}{{/* IsBaseType */}}
   641  		{{- template "FieldFastWriteBaseType" . -}}
   642  	{{- end}}
   643  {{- end}}{{/* define "FieldFastWrite" */}}
   644  `
   645  
   646  const fieldLength = `
   647  {{define "FieldLength"}}
   648  	{{- if .Type.Category.IsStructLike}}
   649  		{{- template "FieldStructLikeLength" . -}}
   650  	{{- else if .Type.Category.IsContainerType}}
   651  		{{- template "FieldContainerLength" . -}}
   652  	{{- else}}{{/* IsBaseType */}}
   653  		{{- template "FieldBaseTypeLength" . -}}
   654  	{{- end}}
   655  {{- end}}{{/* define "FieldLength" */}}
   656  `
   657  
   658  const fieldFastWriteStructLike = `
   659  {{define "FieldFastWriteStructLike"}}
   660  	offset += {{.Target}}.FastWriteNocopy(buf[offset:], binaryWriter)
   661  {{- end}}{{/* define "FieldFastWriteStructLike" */}}
   662  `
   663  
   664  const fieldStructLikeLength = `
   665  {{define "FieldStructLikeLength"}}
   666  	l += {{.Target}}.BLength()
   667  {{- end}}{{/* define "FieldStructLikeLength" */}}
   668  `
   669  
   670  const fieldFastWriteBaseType = `
   671  {{define "FieldFastWriteBaseType"}}
   672  {{- $Value := .Target}}
   673  {{- if .IsPointer}}{{$Value = printf "*%s" $Value}}{{end}}
   674  {{- if .Type.Category.IsEnum}}{{$Value = printf "int32(%s)" $Value}}{{end}}
   675  {{- if .Type.Category.IsBinary}}{{$Value = printf "[]byte(%s)" $Value}}{{end}}
   676  {{- if IsBinaryOrStringType .Type}}
   677  	offset += bthrift.Binary.Write{{.TypeID}}Nocopy(buf[offset:], binaryWriter, {{$Value}})
   678  {{else}}
   679  	offset += bthrift.Binary.Write{{.TypeID}}(buf[offset:], {{$Value}})
   680  {{end}}
   681  {{- end}}{{/* define "FieldFastWriteBaseType" */}}
   682  `
   683  
   684  const fieldBaseTypeLength = `
   685  {{define "FieldBaseTypeLength"}}
   686  {{- $Value := .Target}}
   687  {{- if .IsPointer}}{{$Value = printf "*%s" $Value}}{{end}}
   688  {{- if .Type.Category.IsEnum}}{{$Value = printf "int32(%s)" $Value}}{{end}}
   689  {{- if .Type.Category.IsBinary}}{{$Value = printf "[]byte(%s)" $Value}}{{end}}
   690  {{- if IsBinaryOrStringType .Type}}
   691  	l += bthrift.Binary.{{.TypeID}}LengthNocopy({{$Value}})
   692  {{else}}
   693  	l += bthrift.Binary.{{.TypeID}}Length({{$Value}})
   694  {{end}}
   695  {{- end}}{{/* define "FieldBaseTypeLength" */}}
   696  `
   697  
   698  const fieldFixedLengthTypeLength = `
   699  {{define "FieldFixedLengthTypeLength"}}
   700  {{- $Value := .Target -}}
   701  bthrift.Binary.{{.TypeID}}Length({{TypeIDToGoType .TypeID}}({{$Value}}))
   702  {{- end -}}{{/* define "FieldFixedLengthTypeLength" */}}
   703  `
   704  
   705  const fieldFastWriteContainer = `
   706  {{define "FieldFastWriteContainer"}}
   707  	{{- if eq "Map" .TypeID}}
   708  		{{- template "FieldFastWriteMap" .}}
   709  	{{- else if eq "List" .TypeID}}
   710  		{{- template "FieldFastWriteList" .}}
   711  	{{- else}}
   712  		{{- template "FieldFastWriteSet" .}}
   713  	{{- end}}
   714  {{- end}}{{/* define "FieldFastWriteContainer" */}}
   715  `
   716  
   717  const fieldContainerLength = `
   718  {{define "FieldContainerLength"}}
   719  	{{- if eq "Map" .TypeID}}
   720  		{{- template "FieldMapLength" .}}
   721  	{{- else if eq "List" .TypeID}}
   722  		{{- template "FieldListLength" .}}
   723  	{{- else}}
   724  		{{- template "FieldSetLength" .}}
   725  	{{- end}}
   726  {{- end}}{{/* define "FieldContainerLength" */}}
   727  `
   728  
   729  const fieldFastWriteMap = `
   730  {{define "FieldFastWriteMap"}}
   731  	mapBeginOffset := offset
   732  	offset += bthrift.Binary.MapBeginLength(thrift.
   733  	{{- .KeyCtx.Type | GetTypeIDConstant -}}
   734  	, thrift.{{- .ValCtx.Type | GetTypeIDConstant -}}, 0)
   735  	var length int
   736  	for k, v := range {{.Target}}{
   737  		length++
   738  		{{$ctx := .KeyCtx.WithTarget "k"}}
   739  		{{- template "FieldFastWrite" $ctx}}
   740  		{{$ctx := .ValCtx.WithTarget "v"}}
   741  		{{- template "FieldFastWrite" $ctx}}
   742  	}
   743  	bthrift.Binary.WriteMapBegin(buf[mapBeginOffset:], thrift.
   744  		{{- .KeyCtx.Type | GetTypeIDConstant -}}
   745  		, thrift.{{- .ValCtx.Type | GetTypeIDConstant -}}
   746  		, length)
   747  	offset += bthrift.Binary.WriteMapEnd(buf[offset:])
   748  {{- end}}{{/* define "FieldFastWriteMap" */}}
   749  `
   750  
   751  const fieldMapLength = `
   752  {{define "FieldMapLength"}}
   753  	l += bthrift.Binary.MapBeginLength(thrift.
   754  		{{- .KeyCtx.Type | GetTypeIDConstant -}}
   755  		, thrift.{{- .ValCtx.Type | GetTypeIDConstant -}}
   756  		, len({{.Target}}))
   757  	{{- if and (IsFixedLengthType .KeyCtx.Type) (IsFixedLengthType .ValCtx.Type)}}
   758  	var tmpK {{.KeyCtx.TypeName}}
   759  	var tmpV {{.ValCtx.TypeName}}
   760  	l += ({{- $ctx := .KeyCtx.WithTarget "tmpK" -}}
   761  		{{- template "FieldFixedLengthTypeLength" $ctx}} +
   762  		{{- $ctx := .ValCtx.WithTarget "tmpV" -}}
   763  		{{- template "FieldFixedLengthTypeLength" $ctx}}) * len({{.Target}})
   764  	{{- else}}
   765  	for k, v := range {{.Target}}{
   766  		{{$ctx := .KeyCtx.WithTarget "k"}}
   767  		{{- template "FieldLength" $ctx}}
   768  		{{$ctx := .ValCtx.WithTarget "v"}}
   769  		{{- template "FieldLength" $ctx}}
   770  	}
   771  	{{- end}}{{/* if */}}
   772  	l += bthrift.Binary.MapEndLength()
   773  {{- end}}{{/* define "FieldMapLength" */}}
   774  `
   775  
   776  const fieldFastWriteSet = `
   777  {{define "FieldFastWriteSet"}}
   778  		setBeginOffset := offset
   779  		offset += bthrift.Binary.SetBeginLength(thrift.
   780  		{{- .ValCtx.Type | GetTypeIDConstant -}}, 0)
   781  		{{template "ValidateSet" .}}
   782  		var length int
   783  		for _, v := range {{.Target}} {
   784  			length++
   785  			{{- $ctx := .ValCtx.WithTarget "v"}}
   786  			{{- template "FieldFastWrite" $ctx}}
   787  		}
   788  		bthrift.Binary.WriteSetBegin(buf[setBeginOffset:], thrift.
   789  		{{- .ValCtx.Type | GetTypeIDConstant -}}
   790  		, length)
   791  		offset += bthrift.Binary.WriteSetEnd(buf[offset:])
   792  {{- end}}{{/* define "FieldFastWriteSet" */}}
   793  `
   794  
   795  const fieldSetLength = `
   796  {{define "FieldSetLength"}}
   797  		l += bthrift.Binary.SetBeginLength(thrift.
   798  		{{- .ValCtx.Type | GetTypeIDConstant -}}
   799  		, len({{.Target}}))
   800  		{{template "ValidateSet" .}}
   801  		{{- if IsFixedLengthType .ValCtx.Type}}
   802  		var tmpV {{.ValCtx.TypeName}}
   803  		l += {{- $ctx := .ValCtx.WithTarget "tmpV" -}}
   804  			{{- template "FieldFixedLengthTypeLength" $ctx -}} * len({{.Target}})
   805  		{{- else}}
   806  		for _, v := range {{.Target}} {
   807  			{{- $ctx := .ValCtx.WithTarget "v"}}
   808  			{{- template "FieldLength" $ctx}}
   809  		}
   810  		{{- end}}{{/* if */}}
   811  		l += bthrift.Binary.SetEndLength()
   812  {{- end}}{{/* define "FieldSetLength" */}}
   813  `
   814  
   815  const fieldFastWriteList = `
   816  {{define "FieldFastWriteList"}}
   817  		listBeginOffset := offset
   818  		offset += bthrift.Binary.ListBeginLength(thrift.
   819  		{{- .ValCtx.Type | GetTypeIDConstant -}}, 0)
   820  		var length int
   821  		for _, v := range {{.Target}} {
   822  			length++
   823  			{{- $ctx := .ValCtx.WithTarget "v"}}
   824  			{{- template "FieldFastWrite" $ctx}}
   825  		}
   826  		bthrift.Binary.WriteListBegin(buf[listBeginOffset:], thrift.
   827  		{{- .ValCtx.Type | GetTypeIDConstant -}}
   828  		, length)
   829  		offset += bthrift.Binary.WriteListEnd(buf[offset:])
   830  {{- end}}{{/* define "FieldFastWriteList" */}}
   831  `
   832  
   833  const fieldListLength = `
   834  {{define "FieldListLength"}}
   835  		l += bthrift.Binary.ListBeginLength(thrift.
   836  		{{- .ValCtx.Type | GetTypeIDConstant -}}
   837  		, len({{.Target}}))
   838  		{{- if IsFixedLengthType .ValCtx.Type}}
   839  		var tmpV {{.ValCtx.TypeName}}
   840  		l += {{- $ctx := .ValCtx.WithTarget "tmpV" -}}
   841  			{{- template "FieldFixedLengthTypeLength" $ctx -}} * len({{.Target}})
   842  		{{- else}}
   843  		for _, v := range {{.Target}} {
   844  			{{- $ctx := .ValCtx.WithTarget "v"}}
   845  			{{- template "FieldLength" $ctx}}
   846  		}
   847  		{{- end}}{{/* if */}}
   848  		l += bthrift.Binary.ListEndLength()
   849  {{- end}}{{/* define "FieldListLength" */}}
   850  `
   851  
   852  const processor = `
   853  {{define "Processor"}}
   854  {{- range .Functions}}
   855  {{$ArgsType := .ArgType}}
   856  {{template "StructLikeCodec" $ArgsType}}
   857  {{- if not .Oneway}}
   858  	{{$ResType := .ResType}}
   859  	{{template "StructLikeCodec" $ResType}}
   860  {{- end}}
   861  {{- end}}{{/* range .Functions */}}
   862  {{- end}}{{/* define "Processor" */}}
   863  `
   864  
   865  const validateSet = `
   866  {{define "ValidateSet"}}
   867  {{- if Features.ValidateSet}}
   868  {{- $ctx := (.ValCtx.WithTarget "tgt").WithSource "src"}}
   869  for i := 0; i < len({{.Target}}); i++ {
   870  	for j := i + 1; j < len({{.Target}}); j++ {
   871  {{- if Features.GenDeepEqual}}
   872  		if func(tgt, src {{$ctx.TypeName}}) bool {
   873  			{{- template "FieldDeepEqual" $ctx}}
   874  			return true
   875  		}({{.Target}}[i], {{.Target}}[j]) {
   876  {{- else}}
   877  		if reflect.DeepEqual({{.Target}}[i], {{.Target}}[j]) {
   878  {{- end}}
   879  			panic(fmt.Errorf("%T error writing set field: slice is not unique", {{.Target}}[i]))
   880  		}
   881  	}
   882  }
   883  {{- end}}
   884  {{- end}}{{/* define "ValidateSet" */}}`