reflect_struct_encoder.go raw

   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  }
 212