github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/msgfmt/jsonfmt/encoder.go (about) 1 package jsonfmt 2 3 import ( 4 "unsafe" 5 "reflect" 6 "strings" 7 "unicode" 8 "fmt" 9 "encoding/json" 10 "context" 11 "github.com/v2pro/plz/reflect2" 12 "github.com/v2pro/plz/concurrent" 13 ) 14 15 var bytesType = reflect2.TypeOf([]byte(nil)) 16 var errorType = reflect2.TypeOfPtr((*error)(nil)).Elem() 17 var jsonMarshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem() 18 19 type Encoder interface { 20 Encode(ctx context.Context, space []byte, ptr unsafe.Pointer) []byte 21 } 22 23 type Extension interface { 24 EncoderOf(prefix string, valType reflect.Type) Encoder 25 } 26 27 type Config struct { 28 IncludesUnexported bool 29 Extensions []Extension 30 } 31 32 type API interface { 33 EncoderOf(valType reflect2.Type) Encoder 34 EncoderOfObject(obj interface{}) Encoder 35 } 36 37 var ConfigDefault = Config{}.Froze() 38 39 40 type frozenConfig struct { 41 includesUnexported bool 42 extensions []Extension 43 encoderCache *concurrent.Map 44 mapKeyEncoderCache *concurrent.Map 45 } 46 47 func (cfg Config) Froze() API { 48 return &frozenConfig{ 49 includesUnexported: cfg.IncludesUnexported, 50 extensions: cfg.Extensions, 51 encoderCache: concurrent.NewMap(), 52 mapKeyEncoderCache: concurrent.NewMap(), 53 } 54 } 55 56 func (cfg *frozenConfig) EncoderOfObject(obj interface{}) Encoder { 57 cacheKey := reflect2.RTypeOf(obj) 58 encoderObj, found := cfg.encoderCache.Load(cacheKey) 59 if found { 60 return encoderObj.(Encoder) 61 } 62 return cfg.EncoderOf(reflect2.TypeOf(obj)) 63 } 64 65 func (cfg *frozenConfig) EncoderOf(valType reflect2.Type) Encoder { 66 cacheKey := valType.RType() 67 encoderObj, found := cfg.encoderCache.Load(cacheKey) 68 if found { 69 return encoderObj.(Encoder) 70 } 71 encoder := encoderOf(cfg, "", valType) 72 if valType.LikePtr() { 73 encoder = &onePtrInterfaceEncoder{encoder} 74 } 75 cfg.encoderCache.Store(cacheKey, encoder) 76 return encoder 77 } 78 79 func encoderOfMapKey(cfg *frozenConfig, prefix string, keyType reflect2.Type) Encoder { 80 cacheKey := keyType.RType() 81 encoderObj, found := cfg.mapKeyEncoderCache.Load(cacheKey) 82 if found { 83 return encoderObj.(Encoder) 84 } 85 encoder := _encoderOfMapKey(cfg, prefix, keyType) 86 cfg.mapKeyEncoderCache.Store(cacheKey, encoder) 87 return encoder 88 } 89 90 func EncoderOf(valType reflect2.Type) Encoder { 91 return ConfigDefault.EncoderOf(valType) 92 } 93 94 func EncoderOfObject(obj interface{}) Encoder { 95 return ConfigDefault.EncoderOfObject(obj) 96 } 97 98 func MarshalToString(obj interface{}) string { 99 encoder := EncoderOfObject(obj) 100 return string(encoder.Encode(nil, nil, reflect2.PtrOf(obj))) 101 } 102 103 func encoderOf(cfg *frozenConfig, prefix string, valType reflect2.Type) Encoder { 104 for _, extension := range cfg.extensions { 105 encoder := extension.EncoderOf(prefix, valType.Type1()) 106 if encoder != nil { 107 return encoder 108 } 109 } 110 if bytesType == valType { 111 return &bytesEncoder{} 112 } 113 if valType.Implements(errorType) { 114 return &errorEncoder{ 115 valType: valType, 116 } 117 } 118 if valType.Implements(jsonMarshalerType) { 119 return &jsonMarshalerEncoder{ 120 valType: valType, 121 } 122 } 123 switch valType.Kind() { 124 case reflect.Bool: 125 return &boolEncoder{} 126 case reflect.Int8: 127 return &int8Encoder{} 128 case reflect.Uint8: 129 return &uint8Encoder{} 130 case reflect.Int16: 131 return &int16Encoder{} 132 case reflect.Uint16: 133 return &uint16Encoder{} 134 case reflect.Int32: 135 return &int32Encoder{} 136 case reflect.Uint32: 137 return &uint32Encoder{} 138 case reflect.Int64, reflect.Int: 139 return &int64Encoder{} 140 case reflect.Uint64, reflect.Uint, reflect.Uintptr: 141 return &uint64Encoder{} 142 case reflect.Float64: 143 return &lossyFloat64Encoder{} 144 case reflect.Float32: 145 return &lossyFloat32Encoder{} 146 case reflect.String: 147 return &stringEncoder{} 148 case reflect.Ptr: 149 pointerType := valType.(reflect2.PtrType) 150 elemEncoder := encoderOf(cfg, prefix+" [ptrElem]", pointerType.Elem()) 151 return &pointerEncoder{elemEncoder: elemEncoder} 152 case reflect.Slice: 153 sliceType := valType.(reflect2.SliceType) 154 elemEncoder := encoderOf(cfg, prefix+" [sliceElem]", sliceType.Elem()) 155 return &sliceEncoder{ 156 elemEncoder: elemEncoder, 157 sliceType: sliceType.(*reflect2.UnsafeSliceType), 158 } 159 case reflect.Array: 160 arrayType := valType.(reflect2.ArrayType) 161 elemEncoder := encoderOf(cfg, prefix+" [sliceElem]", arrayType.Elem()) 162 return &arrayEncoder{ 163 elemEncoder: elemEncoder, 164 arrayType: arrayType.(*reflect2.UnsafeArrayType), 165 } 166 case reflect.Struct: 167 structType := valType.(reflect2.StructType) 168 return encoderOfStruct(cfg, prefix, structType) 169 case reflect.Map: 170 mapType := valType.(reflect2.MapType) 171 return encoderOfMap(cfg, prefix, mapType) 172 case reflect.Interface: 173 return &dynamicEncoder{valType:valType} 174 } 175 return &unsupportedEncoder{fmt.Sprintf(`"can not encode %s %s to json"`, valType.String(), prefix)} 176 } 177 178 type unsupportedEncoder struct { 179 msg string 180 } 181 182 func (encoder *unsupportedEncoder) Encode(ctx context.Context, space []byte, ptr unsafe.Pointer) []byte { 183 return append(space, encoder.msg...) 184 } 185 186 func encoderOfMap(cfg *frozenConfig, prefix string, valType reflect2.MapType) *mapEncoder { 187 keyEncoder := encoderOfMapKey(cfg, prefix, valType.Key()) 188 elemType := valType.Elem() 189 elemEncoder := encoderOf(cfg, prefix+" [mapElem]", elemType) 190 return &mapEncoder{ 191 keyEncoder: keyEncoder, 192 elemEncoder: elemEncoder, 193 mapType: valType.(*reflect2.UnsafeMapType), 194 } 195 } 196 197 func _encoderOfMapKey(cfg *frozenConfig, prefix string, keyType reflect2.Type) Encoder { 198 keyEncoder := encoderOf(cfg, prefix+" [mapKey]", keyType) 199 if keyType.Kind() == reflect.String || keyType == bytesType { 200 return &mapStringKeyEncoder{keyEncoder} 201 } 202 if keyType.Kind() == reflect.Interface { 203 return &mapInterfaceKeyEncoder{cfg: cfg, prefix: prefix} 204 } 205 return &mapNumberKeyEncoder{keyEncoder} 206 } 207 208 type onePtrInterfaceEncoder struct { 209 valEncoder Encoder 210 } 211 212 func (encoder *onePtrInterfaceEncoder) Encode(ctx context.Context, space []byte, ptr unsafe.Pointer) []byte { 213 return encoder.valEncoder.Encode(ctx, space, unsafe.Pointer(&ptr)) 214 } 215 216 func encoderOfStruct(cfg *frozenConfig, prefix string, valType reflect2.StructType) *structEncoder { 217 var fields []structEncoderField 218 for i := 0; i < valType.NumField(); i++ { 219 field := valType.Field(i) 220 name := getFieldName(cfg, field) 221 if name == "" { 222 continue 223 } 224 prefix := "" 225 if len(fields) != 0 { 226 prefix += "," 227 } 228 prefix += `"` 229 prefix += name 230 prefix += `":` 231 fields = append(fields, structEncoderField{ 232 structField: field.(*reflect2.UnsafeStructField), 233 prefix: prefix, 234 encoder: encoderOf(cfg, prefix+" ."+name, field.Type()), 235 }) 236 } 237 return &structEncoder{ 238 fields: fields, 239 } 240 } 241 242 func getFieldName(cfg *frozenConfig, field reflect2.StructField) string { 243 if !cfg.includesUnexported && !unicode.IsUpper(rune(field.Name()[0])) { 244 return "" 245 } 246 if field.Type().Kind() == reflect.Func { 247 return "" 248 } 249 if field.Type().Kind() == reflect.Chan { 250 return "" 251 } 252 jsonTag := field.Tag().Get("json") 253 if jsonTag == "" { 254 return field.Name() 255 } 256 parts := strings.Split(jsonTag, ",") 257 if parts[0] == "-" { 258 return "" 259 } 260 if parts[0] == "" { 261 return field.Name() 262 } 263 return parts[0] 264 }