github.com/lingyao2333/mo-zero@v1.4.1/core/mapping/marshaler.go (about) 1 package mapping 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 ) 8 9 const ( 10 emptyTag = "" 11 tagKVSeparator = ":" 12 ) 13 14 // Marshal marshals the given val and returns the map that contains the fields. 15 // optional=another is not implemented, and it's hard to implement and not common used. 16 func Marshal(val interface{}) (map[string]map[string]interface{}, error) { 17 ret := make(map[string]map[string]interface{}) 18 tp := reflect.TypeOf(val) 19 if tp.Kind() == reflect.Ptr { 20 tp = tp.Elem() 21 } 22 rv := reflect.ValueOf(val) 23 if rv.Kind() == reflect.Ptr { 24 rv = rv.Elem() 25 } 26 27 for i := 0; i < tp.NumField(); i++ { 28 field := tp.Field(i) 29 value := rv.Field(i) 30 if err := processMember(field, value, ret); err != nil { 31 return nil, err 32 } 33 } 34 35 return ret, nil 36 } 37 38 func getTag(field reflect.StructField) (string, bool) { 39 tag := string(field.Tag) 40 if i := strings.Index(tag, tagKVSeparator); i >= 0 { 41 return strings.TrimSpace(tag[:i]), true 42 } 43 44 return strings.TrimSpace(tag), false 45 } 46 47 func processMember(field reflect.StructField, value reflect.Value, 48 collector map[string]map[string]interface{}) error { 49 var key string 50 var opt *fieldOptions 51 var err error 52 tag, ok := getTag(field) 53 if !ok { 54 tag = emptyTag 55 key = field.Name 56 } else { 57 key, opt, err = parseKeyAndOptions(tag, field) 58 if err != nil { 59 return err 60 } 61 62 if err = validate(field, value, opt); err != nil { 63 return err 64 } 65 } 66 67 val := value.Interface() 68 if opt != nil && opt.FromString { 69 val = fmt.Sprint(val) 70 } 71 72 m, ok := collector[tag] 73 if ok { 74 m[key] = val 75 } else { 76 m = map[string]interface{}{ 77 key: val, 78 } 79 } 80 collector[tag] = m 81 82 return nil 83 } 84 85 func validate(field reflect.StructField, value reflect.Value, opt *fieldOptions) error { 86 if opt == nil || !opt.Optional { 87 if err := validateOptional(field, value); err != nil { 88 return err 89 } 90 } 91 92 if opt == nil { 93 return nil 94 } 95 96 if opt.Optional && value.IsZero() { 97 return nil 98 } 99 100 if len(opt.Options) > 0 { 101 if err := validateOptions(value, opt); err != nil { 102 return err 103 } 104 } 105 106 if opt.Range != nil { 107 if err := validateRange(value, opt); err != nil { 108 return err 109 } 110 } 111 112 return nil 113 } 114 115 func validateOptional(field reflect.StructField, value reflect.Value) error { 116 switch field.Type.Kind() { 117 case reflect.Ptr: 118 if value.IsNil() { 119 return fmt.Errorf("field %q is nil", field.Name) 120 } 121 case reflect.Array, reflect.Slice, reflect.Map: 122 if value.IsNil() || value.Len() == 0 { 123 return fmt.Errorf("field %q is empty", field.Name) 124 } 125 } 126 127 return nil 128 } 129 130 func validateOptions(value reflect.Value, opt *fieldOptions) error { 131 var found bool 132 val := fmt.Sprint(value.Interface()) 133 for i := range opt.Options { 134 if opt.Options[i] == val { 135 found = true 136 break 137 } 138 } 139 if !found { 140 return fmt.Errorf("field %q not in options", val) 141 } 142 143 return nil 144 } 145 146 func validateRange(value reflect.Value, opt *fieldOptions) error { 147 var val float64 148 switch v := value.Interface().(type) { 149 case int: 150 val = float64(v) 151 case int8: 152 val = float64(v) 153 case int16: 154 val = float64(v) 155 case int32: 156 val = float64(v) 157 case int64: 158 val = float64(v) 159 case uint: 160 val = float64(v) 161 case uint8: 162 val = float64(v) 163 case uint16: 164 val = float64(v) 165 case uint32: 166 val = float64(v) 167 case uint64: 168 val = float64(v) 169 case float32: 170 val = float64(v) 171 case float64: 172 val = v 173 default: 174 return fmt.Errorf("unknown support type for range %q", value.Type().String()) 175 } 176 177 // validates [left, right], [left, right), (left, right], (left, right) 178 if val < opt.Range.left || 179 (!opt.Range.leftInclude && val == opt.Range.left) || 180 val > opt.Range.right || 181 (!opt.Range.rightInclude && val == opt.Range.right) { 182 return fmt.Errorf("%v out of range", value.Interface()) 183 } 184 185 return nil 186 }