github.com/vcilabs/webrpc@v0.5.2-0.20201116131534-162e27b1b33b/gen/golang/funcmap.go (about)

     1  package golang
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sort"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/webrpc/webrpc/schema"
    11  )
    12  
    13  var fieldTypeMap = map[schema.DataType]string{
    14  	schema.T_Uint:      "uint",
    15  	schema.T_Uint8:     "uint8",
    16  	schema.T_Uint16:    "uint16",
    17  	schema.T_Uint32:    "uint32",
    18  	schema.T_Uint64:    "uint64",
    19  	schema.T_Int:       "int",
    20  	schema.T_Int8:      "int8",
    21  	schema.T_Int16:     "int16",
    22  	schema.T_Int32:     "int32",
    23  	schema.T_Int64:     "int64",
    24  	schema.T_Float32:   "float32",
    25  	schema.T_Float64:   "float64",
    26  	schema.T_String:    "string",
    27  	schema.T_Timestamp: "time.Time",
    28  	schema.T_Null:      "struct{}",
    29  	schema.T_Any:       "interface{}",
    30  	schema.T_Byte:      "byte",
    31  	schema.T_Bool:      "bool",
    32  }
    33  
    34  func serviceMethodName(in schema.VarName) (string, error) {
    35  	s := string(in)
    36  	return "serve" + strings.ToUpper(s[0:1]) + s[1:], nil
    37  }
    38  
    39  func serviceMethodJSONName(in schema.VarName) (string, error) {
    40  	s := string(in)
    41  	return "serve" + strings.ToUpper(s[0:1]) + s[1:] + "JSON", nil
    42  }
    43  
    44  func newServerServiceName(in schema.VarName) (string, error) {
    45  	return "New" + string(in) + "Server", nil
    46  }
    47  
    48  func newClientServiceName(in schema.VarName) (string, error) {
    49  	return "New" + string(in) + "Client", nil
    50  }
    51  
    52  func fieldType(in *schema.VarType) (string, error) {
    53  	switch in.Type {
    54  	case schema.T_Map:
    55  		typK, ok := fieldTypeMap[in.Map.Key]
    56  		if !ok {
    57  			return "", fmt.Errorf("unknown type mapping %v", in.Map.Key)
    58  		}
    59  		typV, err := fieldType(in.Map.Value)
    60  		if err != nil {
    61  			return "", err
    62  		}
    63  		return fmt.Sprintf("map[%v]%s", typK, typV), nil
    64  
    65  	case schema.T_List:
    66  		z, err := fieldType(in.List.Elem)
    67  		if err != nil {
    68  			return "", err
    69  		}
    70  		return "[]" + z, nil
    71  
    72  	case schema.T_Struct:
    73  		return "*" + in.Struct.Name, nil
    74  
    75  	case schema.T_UserDefined:
    76  		return in.UserDefined.Name, nil
    77  
    78  	default:
    79  		if fieldTypeMap[in.Type] != "" {
    80  			return fieldTypeMap[in.Type], nil
    81  		}
    82  	}
    83  	return "", fmt.Errorf("could not represent type: %#v", in)
    84  }
    85  
    86  func fieldOptional(field *schema.MessageField) (string, error) {
    87  	if !field.Optional {
    88  		return "", nil
    89  	}
    90  	switch field.Type.Type {
    91  	case schema.T_Map:
    92  		return "", nil // noop
    93  	case schema.T_List:
    94  		return "", nil // noop
    95  	case schema.T_Struct:
    96  		return "", nil // noop because by default struct uses '*' prefix
    97  	default:
    98  		if fieldTypeMap[field.Type.Type] != "" {
    99  			return "*", nil
   100  		}
   101  	}
   102  	return "", fmt.Errorf("could not represent type: %#v", field)
   103  }
   104  
   105  func fieldTypeDef(in *schema.MessageField) (string, error) {
   106  	goFieldType := ""
   107  
   108  	meta := in.Meta
   109  	for kk := range meta {
   110  		for k, v := range meta[kk] {
   111  			if k == "go.field.type" {
   112  				goFieldType = fmt.Sprintf("%v", v)
   113  			}
   114  		}
   115  	}
   116  
   117  	if goFieldType != "" {
   118  		return goFieldType, nil
   119  	}
   120  
   121  	return fieldType(in.Type)
   122  }
   123  
   124  func fieldTags(in *schema.MessageField) (string, error) {
   125  	fieldTags := map[string]interface{}{}
   126  
   127  	jsonFieldName, err := downcaseName(in.Name)
   128  	if err != nil {
   129  		return "", err
   130  	}
   131  	fieldTags["json"] = fmt.Sprintf("%s", jsonFieldName)
   132  
   133  	goTagJSON := ""
   134  
   135  	meta := in.Meta
   136  	for kk := range meta {
   137  		for k, v := range meta[kk] {
   138  
   139  			switch {
   140  			case k == "json":
   141  				if goTagJSON == "" {
   142  					fieldTags["json"] = fmt.Sprintf("%v", v)
   143  				}
   144  
   145  			case strings.HasPrefix(k, "go.tag.json"):
   146  				goTagJSON = fmt.Sprintf("%v", v)
   147  				if !strings.HasPrefix(goTagJSON, fmt.Sprintf("%v", fieldTags["json"])) {
   148  					return "", errors.New("go.tag.json is invalid, it must match the json fieldname")
   149  				}
   150  				fieldTags[k[7:]] = fmt.Sprintf("%v", v)
   151  
   152  			case strings.HasPrefix(k, "go.tag."):
   153  				if k == "go.tag.json" {
   154  					goTagJSON = fmt.Sprintf("%v", v)
   155  				}
   156  				fieldTags[k[7:]] = fmt.Sprintf("%v", v)
   157  			}
   158  
   159  		}
   160  	}
   161  
   162  	tagKeys := []string{}
   163  	for k, _ := range fieldTags {
   164  		if k != "json" {
   165  			tagKeys = append(tagKeys, k)
   166  		}
   167  	}
   168  	sort.StringSlice(tagKeys).Sort()
   169  	tagKeys = append([]string{"json"}, tagKeys...)
   170  
   171  	tags := []string{}
   172  	for _, k := range tagKeys {
   173  		tags = append(tags, fmt.Sprintf(`%s:"%v"`, k, fieldTags[k]))
   174  	}
   175  
   176  	return "`" + strings.Join(tags, " ") + "`", nil
   177  }
   178  
   179  func constPathPrefix(in schema.VarName) (string, error) {
   180  	return string(in) + "PathPrefix", nil
   181  }
   182  
   183  func countMethods(in []*schema.Method) (string, error) {
   184  	return strconv.Itoa(len(in)), nil
   185  }
   186  
   187  func clientServiceName(in schema.VarName) (string, error) {
   188  	s := string(in)
   189  	return strings.ToLower(s[0:1]) + s[1:] + "Client", nil
   190  }
   191  
   192  func serverServiceName(in schema.VarName) (string, error) {
   193  	s := string(in)
   194  	return strings.ToLower(s[0:1]) + s[1:] + "Server", nil
   195  }
   196  
   197  func methodArgName(in *schema.MethodArgument) string {
   198  	name := string(in.Name)
   199  	if name == "" && in.Type != nil {
   200  		name = in.Type.String()
   201  	}
   202  	if name != "" {
   203  		return name
   204  	}
   205  	return ""
   206  }
   207  
   208  func methodArgType(in *schema.MethodArgument) string {
   209  	z, err := fieldType(in.Type)
   210  	if err != nil {
   211  		panic(err.Error())
   212  	}
   213  
   214  	var prefix string
   215  	typ := in.Type.Type
   216  
   217  	if in.Optional {
   218  		prefix = "*"
   219  	}
   220  	if typ == schema.T_Struct {
   221  		prefix = "" // noop, as already pointer applied elsewhere
   222  	}
   223  	if typ == schema.T_List || typ == schema.T_Map {
   224  		prefix = ""
   225  	}
   226  
   227  	return prefix + z
   228  }
   229  
   230  func methodInputs(in []*schema.MethodArgument) (string, error) {
   231  	inputs := []string{"ctx context.Context"}
   232  	for i := range in {
   233  		inputs = append(inputs, fmt.Sprintf("%s %s", methodArgName(in[i]), methodArgType(in[i])))
   234  	}
   235  	return strings.Join(inputs, ", "), nil
   236  }
   237  
   238  func methodOutputs(in []*schema.MethodArgument) (string, error) {
   239  	outputs := []string{}
   240  	for i := range in {
   241  		outputs = append(outputs, methodArgType(in[i]))
   242  	}
   243  	outputs = append(outputs, "error")
   244  	return strings.Join(outputs, ", "), nil
   245  }
   246  
   247  func methodArgNames(in []*schema.MethodArgument) (string, error) {
   248  	inputs := []string{}
   249  	for i := range in {
   250  		inputs = append(inputs, fmt.Sprintf("%s", methodArgName(in[i])))
   251  	}
   252  	return strings.Join(inputs, ", "), nil
   253  }
   254  
   255  func argsList(in []*schema.MethodArgument, prefix string) (string, error) {
   256  	ins := []string{}
   257  	for i := range in {
   258  		ins = append(ins, fmt.Sprintf("%s%d", prefix, i))
   259  	}
   260  	return strings.Join(ins, ", "), nil
   261  }
   262  
   263  func commaIfLen(in []*schema.MethodArgument) string {
   264  	if len(in) > 0 {
   265  		return ","
   266  	}
   267  	return ""
   268  }
   269  
   270  func isStruct(t schema.MessageType) bool {
   271  	return t == "struct"
   272  }
   273  
   274  func isAdvancedType(t schema.MessageType) bool {
   275  	return t == "advance"
   276  }
   277  
   278  func exportedField(in *schema.MessageField) (string, error) {
   279  	s := string(in.Name)
   280  	s = strings.ToUpper(s[0:1]) + s[1:]
   281  
   282  	nameTag := "go.field.name"
   283  	for k := range in.Meta {
   284  		for k, v := range in.Meta[k] {
   285  			if k == nameTag {
   286  				s = fmt.Sprintf("%v", v)
   287  			}
   288  		}
   289  	}
   290  
   291  	return s, nil
   292  }
   293  
   294  func downcaseName(v interface{}) (string, error) {
   295  	downFn := func(s string) string {
   296  		if s == "" {
   297  			return ""
   298  		}
   299  		return strings.ToLower(s[0:1]) + s[1:]
   300  	}
   301  	switch t := v.(type) {
   302  	case schema.VarName:
   303  		return downFn(string(t)), nil
   304  	case string:
   305  		return downFn(t), nil
   306  	default:
   307  		return "", errors.New("downcaseFieldName, unknown arg type")
   308  	}
   309  }
   310  
   311  func isEnum(t schema.MessageType) bool {
   312  	return t == "enum"
   313  }
   314  
   315  func hasFieldType(proto *schema.WebRPCSchema) func(fieldType string) (bool, error) {
   316  	return func(fieldType string) (bool, error) {
   317  		return proto.HasFieldType(fieldType)
   318  	}
   319  }
   320  
   321  func templateFuncMap(proto *schema.WebRPCSchema) map[string]interface{} {
   322  	return map[string]interface{}{
   323  		"serviceMethodName":     serviceMethodName,
   324  		"serviceMethodJSONName": serviceMethodJSONName,
   325  		"hasFieldType":          hasFieldType(proto),
   326  		"fieldTags":             fieldTags,
   327  		"fieldType":             fieldType,
   328  		"fieldOptional":         fieldOptional,
   329  		"fieldTypeDef":          fieldTypeDef,
   330  		"newClientServiceName":  newClientServiceName,
   331  		"newServerServiceName":  newServerServiceName,
   332  		"constPathPrefix":       constPathPrefix,
   333  		"countMethods":          countMethods,
   334  		"clientServiceName":     clientServiceName,
   335  		"serverServiceName":     serverServiceName,
   336  		"methodInputs":          methodInputs,
   337  		"methodOutputs":         methodOutputs,
   338  		"methodArgName":         methodArgName,
   339  		"methodArgType":         methodArgType,
   340  		"methodArgNames":        methodArgNames,
   341  		"argsList":              argsList,
   342  		"commaIfLen":            commaIfLen,
   343  		"isStruct":              isStruct,
   344  		"isAdvancedType":        isAdvancedType,
   345  		"isEnum":                isEnum,
   346  		"exportedField":         exportedField,
   347  		"downcaseName":          downcaseName,
   348  	}
   349  }