...

Source file src/github.com/json-iterator/go/reflect_struct_encoder.go

Documentation: github.com/json-iterator/go

     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  

View as plain text