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  }