1 Star 0 Fork 0

go-better/go

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
index.go 3.79 KB
一键复制 编辑 原始数据 按行查看 历史
bughou 提交于 3年前 . 迁移完成
package funcs
import (
"encoding"
"reflect"
"sync"
"gitee.com/go-better/dev/encoding/jsondoc/encoder/types"
)
type encoderFunc func(buf *types.Buffer, v reflect.Value, opts types.Options)
func Of(v reflect.Value) encoderFunc {
if !v.IsValid() {
return invalidValueEncoder
}
return typeEncoder(v.Type())
}
var encoderCache sync.Map // map[reflect.Type]encoderFunc
func typeEncoder(t reflect.Type) encoderFunc {
if fi, ok := encoderCache.Load(t); ok {
return fi.(encoderFunc)
}
// To deal with recursive types, populate the map with an
// indirect func before we build it. This type waits on the
// real func (f) to be ready and then calls it. This indirect
// func is only used for recursive types.
var (
wg sync.WaitGroup
f encoderFunc
)
wg.Add(1)
fi, loaded := encoderCache.LoadOrStore(t, encoderFunc(func(buf *types.Buffer, v reflect.Value, opts types.Options) {
wg.Wait()
f(buf, v, opts)
}))
if loaded {
return fi.(encoderFunc)
}
// Compute the real encoder and replace the indirect func with it.
f = newTypeEncoder(t, true)
wg.Done()
encoderCache.Store(t, f)
return f
}
var (
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
)
// newTypeEncoder constructs an encoderFunc for a type.
// The returned encoder only checks CanAddr when allowAddr is true.
func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
if t.Implements(marshalerType) {
return marshalerEncoder
}
if t.Kind() != reflect.Ptr && allowAddr {
if reflect.PtrTo(t).Implements(marshalerType) {
return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false))
}
}
if t.Implements(textMarshalerType) {
return textMarshalerEncoder
}
if t.Kind() != reflect.Ptr && allowAddr {
if reflect.PtrTo(t).Implements(textMarshalerType) {
return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false))
}
}
switch t.Kind() {
case reflect.Bool:
return boolEncoder
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return intEncoder
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return uintEncoder
case reflect.Float32:
return float32Encoder
case reflect.Float64:
return float64Encoder
case reflect.String:
return stringEncoder
case reflect.Interface:
return interfaceEncoder
case reflect.Struct:
return newStructEncoder(t)
case reflect.Map:
return newMapEncoder(t)
case reflect.Slice:
return newSliceEncoder(t)
case reflect.Array:
return newArrayEncoder(t)
case reflect.Ptr:
return newPtrEncoder(t)
default:
return unsupportedTypeEncoder
}
}
func newPtrEncoder(t reflect.Type) encoderFunc {
enc := ptrEncoder{typeEncoder(t.Elem())}
return enc.encode
}
type ptrEncoder struct {
elemEnc encoderFunc
}
func (pe ptrEncoder) encode(buf *types.Buffer, v reflect.Value, opts types.Options) {
if v.IsNil() {
typ := v.Type()
if opts.NotRecursion(typ) {
v = reflect.New(typ.Elem())
opts.AppendConvertedTypeInUpperLayers(typ)
}
}
if v.IsNil() {
buf.WriteString("null")
return
}
pe.elemEnc(buf, v.Elem(), opts)
}
func interfaceEncoder(buf *types.Buffer, v reflect.Value, opts types.Options) {
if v.IsNil() {
buf.WriteString("null")
return
}
v = v.Elem()
Of(v)(buf, v, opts)
}
func unsupportedTypeEncoder(buf *types.Buffer, v reflect.Value, _ types.Options) {
raiseError(&UnsupportedTypeError{v.Type()})
}
// An UnsupportedTypeError is returned by Marshal when attempting
// to encode an unsupported value type.
type UnsupportedTypeError struct {
Type reflect.Type
}
func (e *UnsupportedTypeError) Error() string {
return "json: unsupported type: " + e.Type.String()
}
func invalidValueEncoder(buf *types.Buffer, v reflect.Value, _ types.Options) {
buf.WriteString("null")
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/go-better/go.git
git@gitee.com:go-better/go.git
go-better
go
go
d31700df43a9

搜索帮助