gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

reflect_struct_encoder.go (5295B)


      1 package jsoniter
      2 
      3 import (
      4 	"fmt"
      5 	"github.com/modern-go/reflect2"
      6 	"io"
      7 	"reflect"
      8 	"unsafe"
      9 )
     10 
     11 func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder {
     12 	type bindingTo struct {
     13 		binding *Binding
     14 		toName  string
     15 		ignored bool
     16 	}
     17 	orderedBindings := []*bindingTo{}
     18 	structDescriptor := describeStruct(ctx, typ)
     19 	for _, binding := range structDescriptor.Fields {
     20 		for _, toName := range binding.ToNames {
     21 			new := &bindingTo{
     22 				binding: binding,
     23 				toName:  toName,
     24 			}
     25 			for _, old := range orderedBindings {
     26 				if old.toName != toName {
     27 					continue
     28 				}
     29 				old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding)
     30 			}
     31 			orderedBindings = append(orderedBindings, new)
     32 		}
     33 	}
     34 	if len(orderedBindings) == 0 {
     35 		return &emptyStructEncoder{}
     36 	}
     37 	finalOrderedFields := []structFieldTo{}
     38 	for _, bindingTo := range orderedBindings {
     39 		if !bindingTo.ignored {
     40 			finalOrderedFields = append(finalOrderedFields, structFieldTo{
     41 				encoder: bindingTo.binding.Encoder.(*structFieldEncoder),
     42 				toName:  bindingTo.toName,
     43 			})
     44 		}
     45 	}
     46 	return &structEncoder{typ, finalOrderedFields}
     47 }
     48 
     49 func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty {
     50 	encoder := createEncoderOfNative(ctx, typ)
     51 	if encoder != nil {
     52 		return encoder
     53 	}
     54 	kind := typ.Kind()
     55 	switch kind {
     56 	case reflect.Interface:
     57 		return &dynamicEncoder{typ}
     58 	case reflect.Struct:
     59 		return &structEncoder{typ: typ}
     60 	case reflect.Array:
     61 		return &arrayEncoder{}
     62 	case reflect.Slice:
     63 		return &sliceEncoder{}
     64 	case reflect.Map:
     65 		return encoderOfMap(ctx, typ)
     66 	case reflect.Ptr:
     67 		return &OptionalEncoder{}
     68 	default:
     69 		return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", typ)}
     70 	}
     71 }
     72 
     73 func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) {
     74 	newTagged := new.Field.Tag().Get(cfg.getTagKey()) != ""
     75 	oldTagged := old.Field.Tag().Get(cfg.getTagKey()) != ""
     76 	if newTagged {
     77 		if oldTagged {
     78 			if len(old.levels) > len(new.levels) {
     79 				return true, false
     80 			} else if len(new.levels) > len(old.levels) {
     81 				return false, true
     82 			} else {
     83 				return true, true
     84 			}
     85 		} else {
     86 			return true, false
     87 		}
     88 	} else {
     89 		if oldTagged {
     90 			return true, false
     91 		}
     92 		if len(old.levels) > len(new.levels) {
     93 			return true, false
     94 		} else if len(new.levels) > len(old.levels) {
     95 			return false, true
     96 		} else {
     97 			return true, true
     98 		}
     99 	}
    100 }
    101 
    102 type structFieldEncoder struct {
    103 	field        reflect2.StructField
    104 	fieldEncoder ValEncoder
    105 	omitempty    bool
    106 }
    107 
    108 func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
    109 	fieldPtr := encoder.field.UnsafeGet(ptr)
    110 	encoder.fieldEncoder.Encode(fieldPtr, stream)
    111 	if stream.Error != nil && stream.Error != io.EOF {
    112 		stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error())
    113 	}
    114 }
    115 
    116 func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
    117 	fieldPtr := encoder.field.UnsafeGet(ptr)
    118 	return encoder.fieldEncoder.IsEmpty(fieldPtr)
    119 }
    120 
    121 func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
    122 	isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil)
    123 	if !converted {
    124 		return false
    125 	}
    126 	fieldPtr := encoder.field.UnsafeGet(ptr)
    127 	return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
    128 }
    129 
    130 type IsEmbeddedPtrNil interface {
    131 	IsEmbeddedPtrNil(ptr unsafe.Pointer) bool
    132 }
    133 
    134 type structEncoder struct {
    135 	typ    reflect2.Type
    136 	fields []structFieldTo
    137 }
    138 
    139 type structFieldTo struct {
    140 	encoder *structFieldEncoder
    141 	toName  string
    142 }
    143 
    144 func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
    145 	stream.WriteObjectStart()
    146 	isNotFirst := false
    147 	for _, field := range encoder.fields {
    148 		if field.encoder.omitempty && field.encoder.IsEmpty(ptr) {
    149 			continue
    150 		}
    151 		if field.encoder.IsEmbeddedPtrNil(ptr) {
    152 			continue
    153 		}
    154 		if isNotFirst {
    155 			stream.WriteMore()
    156 		}
    157 		stream.WriteObjectField(field.toName)
    158 		field.encoder.Encode(ptr, stream)
    159 		isNotFirst = true
    160 	}
    161 	stream.WriteObjectEnd()
    162 	if stream.Error != nil && stream.Error != io.EOF {
    163 		stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error())
    164 	}
    165 }
    166 
    167 func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool {
    168 	return false
    169 }
    170 
    171 type emptyStructEncoder struct {
    172 }
    173 
    174 func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
    175 	stream.WriteEmptyObject()
    176 }
    177 
    178 func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool {
    179 	return false
    180 }
    181 
    182 type stringModeNumberEncoder struct {
    183 	elemEncoder ValEncoder
    184 }
    185 
    186 func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
    187 	stream.writeByte('"')
    188 	encoder.elemEncoder.Encode(ptr, stream)
    189 	stream.writeByte('"')
    190 }
    191 
    192 func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool {
    193 	return encoder.elemEncoder.IsEmpty(ptr)
    194 }
    195 
    196 type stringModeStringEncoder struct {
    197 	elemEncoder ValEncoder
    198 	cfg         *frozenConfig
    199 }
    200 
    201 func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
    202 	tempStream := encoder.cfg.BorrowStream(nil)
    203 	tempStream.Attachment = stream.Attachment
    204 	defer encoder.cfg.ReturnStream(tempStream)
    205 	encoder.elemEncoder.Encode(ptr, tempStream)
    206 	stream.WriteString(string(tempStream.Buffer()))
    207 }
    208 
    209 func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
    210 	return encoder.elemEncoder.IsEmpty(ptr)
    211 }