nickzuck_007

Struct Tags functions

Jul 8th, 2019
339
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 5.08 KB | None | 0 0
  1. // Function - #1
  2. func getStructInfo(st reflect.Type) (*structInfo, error) {
  3.     structMapMutex.RLock()
  4.     sinfo, found := structMap[st]
  5.     structMapMutex.RUnlock()
  6.     if found {
  7.         return sinfo, nil
  8.     }
  9.     n := st.NumField()
  10.     fieldsMap := make(map[string]fieldInfo)
  11.     fieldsList := make([]fieldInfo, 0, n)
  12.     inlineMap := -1
  13.     for i := 0; i != n; i++ {
  14.         field := st.Field(i)
  15.         if field.PkgPath != "" && !field.Anonymous {
  16.             continue // Private field
  17.         }
  18.  
  19.         info := fieldInfo{Num: i}
  20.  
  21.         tag := field.Tag.Get("bson")
  22.         if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
  23.             tag = string(field.Tag)
  24.         }
  25.         if tag == "-" {
  26.             continue
  27.         }
  28.  
  29.         inline := false
  30.         fields := strings.Split(tag, ",")
  31.         if len(fields) > 1 {
  32.             for _, flag := range fields[1:] {
  33.                 switch flag {
  34.                 case "omitempty":
  35.                     info.OmitEmpty = true
  36.                 case "minsize":
  37.                     info.MinSize = true
  38.                 case "inline":
  39.                     inline = true
  40.                 default:
  41.                     msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)
  42.                     panic(externalPanic(msg))
  43.                 }
  44.             }
  45.             tag = fields[0]
  46.         }
  47.  
  48.         if inline {
  49.             switch field.Type.Kind() {
  50.             case reflect.Map:
  51.                 if inlineMap >= 0 {
  52.                     return nil, errors.New("Multiple ,inline maps in struct " + st.String())
  53.                 }
  54.                 if field.Type.Key() != reflect.TypeOf("") {
  55.                     return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
  56.                 }
  57.                 inlineMap = info.Num
  58.             case reflect.Struct:
  59.                 sinfo, err := getStructInfo(field.Type)
  60.                 if err != nil {
  61.                     return nil, err
  62.                 }
  63.                 for _, finfo := range sinfo.FieldsList {
  64.                     if _, found := fieldsMap[finfo.Key]; found {
  65.                         msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
  66.                         return nil, errors.New(msg)
  67.                     }
  68.                     if finfo.Inline == nil {
  69.                         finfo.Inline = []int{i, finfo.Num}
  70.                     } else {
  71.                         finfo.Inline = append([]int{i}, finfo.Inline...)
  72.                     }
  73.                     fieldsMap[finfo.Key] = finfo
  74.                     fieldsList = append(fieldsList, finfo)
  75.                 }
  76.             default:
  77.                 panic("Option ,inline needs a struct value or map field")
  78.             }
  79.             continue
  80.         }
  81.  
  82.         if tag != "" {
  83.             info.Key = tag
  84.         } else {
  85.             info.Key = strings.ToLower(field.Name)
  86.         }
  87.  
  88.         if _, found = fieldsMap[info.Key]; found {
  89.             msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
  90.             return nil, errors.New(msg)
  91.         }
  92.  
  93.         fieldsList = append(fieldsList, info)
  94.         fieldsMap[info.Key] = info
  95.     }
  96.     sinfo = &structInfo{
  97.         fieldsMap,
  98.         fieldsList,
  99.         inlineMap,
  100.         reflect.New(st).Elem(),
  101.     }
  102.     structMapMutex.Lock()
  103.     structMap[st] = sinfo
  104.     structMapMutex.Unlock()
  105.     return sinfo, nil
  106. }
  107.  
  108. // Function - #2
  109. func (e *encoder) addStruct(v reflect.Value) {
  110.     sinfo, err := getStructInfo(v.Type())
  111.     if err != nil {
  112.         panic(err)
  113.     }
  114.     var value reflect.Value
  115.     if sinfo.InlineMap >= 0 {
  116.         m := v.Field(sinfo.InlineMap)
  117.         if m.Len() > 0 {
  118.             for _, k := range m.MapKeys() {
  119.                 ks := k.String()
  120.                 if _, found := sinfo.FieldsMap[ks]; found {
  121.                     panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks))
  122.                 }
  123.                 e.addElem(ks, m.MapIndex(k), false)
  124.             }
  125.         }
  126.     }
  127.     for _, info := range sinfo.FieldsList {
  128.         if info.Inline == nil {
  129.             value = v.Field(info.Num)
  130.         } else {
  131.             // as pointers to struct are allowed here,
  132.             // there is no guarantee that pointer won't be nil.
  133.             //
  134.             // It is expected allowed behaviour
  135.             // so info.Inline MAY consist index to a nil pointer
  136.             // and that is why we safely call v.FieldByIndex and just continue on panic
  137.             field, errField := safeFieldByIndex(v, info.Inline)
  138.             if errField != nil {
  139.                 continue
  140.             }
  141.  
  142.             value = field
  143.         }
  144.         if info.OmitEmpty && isZero(value) {
  145.             continue
  146.         }
  147.         if useRespectNilValues &&
  148.             (value.Kind() == reflect.Slice || value.Kind() == reflect.Map) &&
  149.             value.IsNil() {
  150.             e.addElem(info.Key, reflect.ValueOf(nil), info.MinSize)
  151.             continue
  152.         }
  153.         e.addElem(info.Key, value, info.MinSize)
  154.     }
  155. }
Advertisement