github.com/cloudwego/frugal@v0.1.15/internal/binary/defs/types.go (about)

     1  /*
     2   * Copyright 2022 ByteDance Inc.
     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 defs
    18  
    19  import (
    20      `fmt`
    21      `reflect`
    22      `strings`
    23      `sync`
    24      `unicode`
    25  
    26      `github.com/cloudwego/frugal/internal/utils`
    27  )
    28  
    29  type Tag uint8
    30  
    31  const (
    32      T_bool    Tag = 2
    33      T_i8      Tag = 3
    34      T_double  Tag = 4
    35      T_i16     Tag = 6
    36      T_i32     Tag = 8
    37      T_i64     Tag = 10
    38      T_string  Tag = 11
    39      T_struct  Tag = 12
    40      T_map     Tag = 13
    41      T_set     Tag = 14
    42      T_list    Tag = 15
    43      T_enum    Tag = 0x80
    44      T_binary  Tag = 0x81
    45      T_pointer Tag = 0x82
    46  )
    47  
    48  var wireTags = [256]bool {
    49      T_bool   : true,
    50      T_i8     : true,
    51      T_double : true,
    52      T_i16    : true,
    53      T_i32    : true,
    54      T_i64    : true,
    55      T_string : true,
    56      T_struct : true,
    57      T_map    : true,
    58      T_set    : true,
    59      T_list   : true,
    60  }
    61  
    62  var keywordTab = [256]string {
    63      T_bool   : "bool",
    64      T_i8     : "i8 byte",
    65      T_double : "double",
    66      T_i16    : "i16",
    67      T_i32    : "i32",
    68      T_i64    : "i64",
    69      T_string : "string",
    70      T_binary : "binary",
    71      T_struct : "struct",
    72      T_map    : "map",
    73  }
    74  
    75  var (
    76      i64type = reflect.TypeOf(int64(0))
    77  )
    78  
    79  func T_int() Tag {
    80      switch IntSize {
    81          case 4  : return T_i32
    82          case 8  : return T_i64
    83          default : panic("invalid int size")
    84      }
    85  }
    86  
    87  func (self Tag) IsWireTag() bool {
    88      return wireTags[self]
    89  }
    90  
    91  type Type struct {
    92      T Tag
    93      K *Type
    94      V *Type
    95      S reflect.Type
    96  }
    97  
    98  var (
    99      typePool sync.Pool
   100  )
   101  
   102  func newType() *Type {
   103      if v := typePool.Get(); v == nil {
   104          return new(Type)
   105      } else {
   106          return resetType(v.(*Type))
   107      }
   108  }
   109  
   110  func resetType(p *Type) *Type {
   111      *p = Type{}
   112      return p
   113  }
   114  
   115  func (self *Type) Tag() Tag {
   116      switch self.T {
   117          case T_enum    : return T_i32
   118          case T_binary  : return T_string
   119          case T_pointer : return self.V.Tag()
   120          default        : return self.T
   121      }
   122  }
   123  
   124  func (self *Type) Free() {
   125      typePool.Put(self)
   126  }
   127  
   128  func (self *Type) String() string {
   129      switch self.T {
   130          case T_bool    : return "bool"
   131          case T_i8      : return "i8"
   132          case T_double  : return "double"
   133          case T_i16     : return "i16"
   134          case T_i32     : return "i32"
   135          case T_i64     : return "i64"
   136          case T_string  : return "string"
   137          case T_struct  : return self.S.Name()
   138          case T_map     : return fmt.Sprintf("map<%s:%s>", self.K.String(), self.V.String())
   139          case T_set     : return fmt.Sprintf("set<%s>", self.V.String())
   140          case T_list    : return fmt.Sprintf("list<%s>", self.V.String())
   141          case T_enum    : return "enum"
   142          case T_binary  : return "binary"
   143          case T_pointer : return "*" + self.V.String()
   144          default        : return fmt.Sprintf("Type(Tag(%d))", self.T)
   145      }
   146  }
   147  
   148  func (self *Type) IsKeyType() bool {
   149      switch self.T {
   150          case T_bool    : return true
   151          case T_i8      : return true
   152          case T_double  : return true
   153          case T_i16     : return true
   154          case T_i32     : return true
   155          case T_i64     : return true
   156          case T_string  : return true
   157          case T_enum    : return true
   158          case T_pointer : return self.V.T == T_struct
   159          default        : return false
   160      }
   161  }
   162  
   163  func (self *Type) IsValueType() bool {
   164      return self.T != T_pointer || self.V.T == T_struct
   165  }
   166  
   167  func (self *Type) IsSimpleType() bool {
   168      switch self.T {
   169          case T_bool    : return true
   170          case T_i8      : return true
   171          case T_double  : return true
   172          case T_i16     : return true
   173          case T_i32     : return true
   174          case T_i64     : return true
   175          case T_string  : return true
   176          case T_enum    : return true
   177          default        : return false
   178      }
   179  }
   180  
   181  func ParseType(vt reflect.Type, def string) (*Type, error) {
   182      var i int
   183      return doParseType(vt, def, &i, true)
   184  }
   185  
   186  func isident(c byte) bool {
   187      return isident0(c) || c >= '0' && c <= '9'
   188  }
   189  
   190  func isident0(c byte) bool {
   191      return c == '_' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'
   192  }
   193  
   194  func readToken(src string, i *int, eofok bool) (string, error) {
   195      p := *i
   196      n := len(src)
   197  
   198      /* skip the spaces */
   199      for p < n && unicode.IsSpace(rune(src[p])) {
   200          p++
   201      }
   202  
   203      /* check for EOF */
   204      if p == n {
   205          if eofok {
   206              return "", nil
   207          } else {
   208              return "", utils.ESyntax(p, src, "unexpected EOF")
   209          }
   210      }
   211  
   212      /* skip the character */
   213      q := p
   214      p++
   215  
   216      /* check for identifiers */
   217      if isident0(src[q]) {
   218          for p < n && isident(src[p]) {
   219              p++
   220          }
   221      }
   222  
   223      /* slice the source */
   224      *i = p
   225      return src[q:p], nil
   226  }
   227  
   228  func mkMistyped(pos int, src string, tv string, tag Tag, vt reflect.Type) utils.SyntaxError {
   229      if tag != T_struct {
   230          return utils.ESyntax(pos, src, fmt.Sprintf("type mismatch, %s expected, got %s", keywordTab[tag], tv))
   231      } else {
   232          return utils.ESyntax(pos, src, fmt.Sprintf("struct name mismatch, %s expected, got %s", vt.Name(), tv))
   233      }
   234  }
   235  
   236  func doParseType(vt reflect.Type, def string, i *int, allowPtrs bool) (*Type, error) {
   237      var tag Tag
   238      var err error
   239      var ret *Type
   240  
   241      /* dereference the pointer if possible */
   242      if ret = newType(); vt.Kind() == reflect.Ptr {
   243          ret.S = vt
   244          ret.T = T_pointer
   245  
   246          /* prohibit nested pointers */
   247          if !allowPtrs {
   248              return nil, utils.EType(ret.V.S, "nested pointer is not allowed")
   249          }
   250  
   251          /* parse the pointer element recursively */
   252          if ret.V, err = doParseType(vt.Elem(), def, i, false); err != nil {
   253              return nil, err
   254          } else {
   255              return ret, nil
   256          }
   257      }
   258  
   259      /* check for value kind */
   260      switch vt.Kind() {
   261          case reflect.Bool    : tag = T_bool
   262          case reflect.Int     : tag = T_int()
   263          case reflect.Int8    : tag = T_i8
   264          case reflect.Int16   : tag = T_i16
   265          case reflect.Int32   : tag = T_i32
   266          case reflect.Int64   : tag = T_i64
   267          case reflect.Uint    : return nil, utils.EUseOther(vt, "int")
   268          case reflect.Uint8   : return nil, utils.EUseOther(vt, "int8")
   269          case reflect.Uint16  : return nil, utils.EUseOther(vt, "int16")
   270          case reflect.Uint32  : return nil, utils.EUseOther(vt, "int32")
   271          case reflect.Uint64  : return nil, utils.EUseOther(vt, "int64")
   272          case reflect.Float32 : return nil, utils.EUseOther(vt, "float64")
   273          case reflect.Float64 : tag = T_double
   274          case reflect.Array   : return nil, utils.EUseOther(vt, "[]" + vt.Elem().String())
   275          case reflect.Map     : tag = T_map
   276          case reflect.Slice   : break
   277          case reflect.String  : tag = T_string
   278          case reflect.Struct  : tag = T_struct
   279          default              : return nil, utils.EType(vt, "unsupported type")
   280      }
   281  
   282      /* it's a slice, check for byte slice */
   283      if tag == 0 {
   284          if et := vt.Elem(); utils.IsByteType(et) {
   285              tag = T_binary
   286          } else if def == "" {
   287              return nil, utils.ESetList(*i, def, et)
   288          } else {
   289              return doParseSlice(vt, et, def, i, ret)
   290          }
   291      }
   292  
   293      /* match the type if any */
   294      if def != "" {
   295          if tv, et := readToken(def, i, false); et != nil {
   296              return nil, et
   297          } else if !strings.Contains(keywordTab[tag], tv) {
   298              if !isident0(tv[0]) {
   299                  return nil, mkMistyped(*i - len(tv), def, tv, tag, vt)
   300              } else if ok, ex := doMatchStruct(vt, def, i, &tv); ex != nil {
   301                  return nil, ex
   302              } else if !ok {
   303                  return nil, mkMistyped(*i - len(tv), def, tv, tag, vt)
   304              } else if tag == T_i64 && vt != i64type {
   305                  tag = T_enum
   306              }
   307          }
   308      }
   309  
   310      /* simple types */
   311      if tag != T_map {
   312          ret.S = vt
   313          ret.T = tag
   314          return ret, nil
   315      }
   316  
   317      /* map begin */
   318      if def != "" {
   319          if tk, et := readToken(def, i, false); et != nil {
   320              return nil, et
   321          } else if tk != "<" {
   322              return nil, utils.ESyntax(*i - len(tk), def, "'<' expected")
   323          }
   324      }
   325  
   326      /* parse the key type */
   327      if ret.K, err = doParseType(vt.Key(), def, i, true); err != nil {
   328          return nil, err
   329      }
   330  
   331      /* validate map key */
   332      if !ret.K.IsKeyType() {
   333          return nil, utils.EType(ret.K.S, "not a valid map key type")
   334      }
   335  
   336      /* key-value delimiter */
   337      if def != "" {
   338          if tk, et := readToken(def, i, false); et != nil {
   339              return nil, et
   340          } else if tk != ":" {
   341              return nil, utils.ESyntax(*i - len(tk), def, "':' expected")
   342          }
   343      }
   344  
   345      /* parse the value type */
   346      if ret.V, err = doParseType(vt.Elem(), def, i, true); err != nil {
   347          return nil, err
   348      }
   349  
   350      /* map end */
   351      if def != "" {
   352          if tk, et := readToken(def, i, false); et != nil {
   353              return nil, et
   354          } else if tk != ">" {
   355              return nil, utils.ESyntax(*i - len(tk), def, "'>' expected")
   356          }
   357      }
   358  
   359      /* check for list elements */
   360      if !ret.V.IsValueType() {
   361          return nil, utils.EType(ret.V.S, "non-struct pointers are not valid map value types")
   362      }
   363  
   364      /* set the type tag */
   365      ret.S = vt
   366      ret.T = T_map
   367      return ret, nil
   368  }
   369  
   370  func doParseSlice(vt reflect.Type, et reflect.Type, def string, i *int, rt *Type) (*Type, error) {
   371      var err error
   372      var tok string
   373  
   374      /* read the next token */
   375      if tok, err = readToken(def, i, false); err != nil {
   376          return nil, err
   377      }
   378  
   379      /* identify "set" or "list" */
   380      if tok == "set" {
   381          rt.T = T_set
   382      } else if tok == "list" {
   383          rt.T = T_list
   384      } else {
   385          return nil, utils.ESyntax(*i - len(tok), def, `"set" or "list" expected`)
   386      }
   387  
   388      /* list or set begin */
   389      if tok, err = readToken(def, i, false); err != nil {
   390          return nil, err
   391      } else if tok != "<" {
   392          return nil, utils.ESyntax(*i - len(tok), def, "'<' expected")
   393      }
   394  
   395      /* set or list element */
   396      if rt.V, err = doParseType(et, def, i, true); err != nil {
   397          return nil, err
   398      }
   399  
   400      /* list or set end */
   401      if tok, err = readToken(def, i, false); err != nil {
   402          return nil, err
   403      } else if tok != ">" {
   404          return nil, utils.ESyntax(*i - len(tok), def, "'>' expected")
   405      }
   406  
   407      /* check for list elements */
   408      if !rt.V.IsValueType() {
   409          return nil, utils.EType(rt.V.S, "non-struct pointers are not valid list/set elements")
   410      }
   411  
   412      /* set the type */
   413      rt.S = vt
   414      return rt, nil
   415  }
   416  
   417  func doMatchStruct(vt reflect.Type, def string, i *int, tv *string) (bool, error) {
   418      var err error
   419      var tok string
   420  
   421      /* mark the starting position */
   422      sp := *i
   423      tn := vt.Name()
   424  
   425      /* read the next token */
   426      if tok, err = readToken(def, &sp, true); err != nil {
   427          return false, err
   428      }
   429  
   430      /* anonymous struct */
   431      if tn == "" && vt.Kind() == reflect.Struct {
   432          return true, nil
   433      }
   434  
   435      /* just a simple type with no qualifiers */
   436      if tok == "" || tok == ":" || tok == ">" {
   437          return tn == *tv, nil
   438      }
   439  
   440      /* otherwise, it must be a "." */
   441      if tok != "." {
   442          return false, utils.ESyntax(sp, def, "'.' or '>' expected")
   443      }
   444  
   445      /* must be an identifier */
   446      if *tv, err = readToken(def, &sp, false); err != nil {
   447          return false, err
   448      } else if !isident0((*tv)[0]) {
   449          return false, utils.ESyntax(sp, def, "struct name expected")
   450      }
   451  
   452      /* update parsing position */
   453      *i = sp
   454      return tn == *tv, nil
   455  }