You've already forked json-iterator
							
							
				mirror of
				https://github.com/json-iterator/go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	fix #207 delay unsupported type error reporting
This commit is contained in:
		
							
								
								
									
										1020
									
								
								feature_reflect.go
									
									
									
									
									
								
							
							
						
						
									
										1020
									
								
								feature_reflect.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -7,23 +7,17 @@ import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| func decoderOfArray(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { | ||||
| 	decoder, err := decoderOfType(cfg, typ.Elem()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &arrayDecoder{typ, typ.Elem(), decoder}, nil | ||||
| func decoderOfArray(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { | ||||
| 	decoder := decoderOfType(cfg, prefix+"[array]->", typ.Elem()) | ||||
| 	return &arrayDecoder{typ, typ.Elem(), decoder} | ||||
| } | ||||
|  | ||||
| func encoderOfArray(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { | ||||
| 	encoder, err := encoderOfType(cfg, typ.Elem()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| func encoderOfArray(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { | ||||
| 	encoder := encoderOfType(cfg, prefix+"[array]->", typ.Elem()) | ||||
| 	if typ.Elem().Kind() == reflect.Map { | ||||
| 		encoder = &OptionalEncoder{encoder} | ||||
| 	} | ||||
| 	return &arrayEncoder{typ, typ.Elem(), encoder}, nil | ||||
| 	return &arrayEncoder{typ, typ.Elem(), encoder} | ||||
| } | ||||
|  | ||||
| type arrayEncoder struct { | ||||
|   | ||||
| @@ -240,7 +240,7 @@ func _getTypeEncoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValEncode | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, error) { | ||||
| func describeStruct(cfg *frozenConfig, prefix string, typ reflect.Type) *StructDescriptor { | ||||
| 	embeddedBindings := []*Binding{} | ||||
| 	bindings := []*Binding{} | ||||
| 	for i := 0; i < typ.NumField(); i++ { | ||||
| @@ -252,10 +252,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err | ||||
| 		} | ||||
| 		if field.Anonymous && (tag == "" || tagParts[0] == "") { | ||||
| 			if field.Type.Kind() == reflect.Struct { | ||||
| 				structDescriptor, err := describeStruct(cfg, field.Type) | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				structDescriptor := describeStruct(cfg, prefix, field.Type) | ||||
| 				for _, binding := range structDescriptor.Fields { | ||||
| 					binding.levels = append([]int{i}, binding.levels...) | ||||
| 					omitempty := binding.Encoder.(*structFieldEncoder).omitempty | ||||
| @@ -265,10 +262,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err | ||||
| 				} | ||||
| 				continue | ||||
| 			} else if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct { | ||||
| 				structDescriptor, err := describeStruct(cfg, field.Type.Elem()) | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				structDescriptor := describeStruct(cfg, prefix, field.Type.Elem()) | ||||
| 				for _, binding := range structDescriptor.Fields { | ||||
| 					binding.levels = append([]int{i}, binding.levels...) | ||||
| 					omitempty := binding.Encoder.(*structFieldEncoder).omitempty | ||||
| @@ -285,19 +279,11 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err | ||||
| 		fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name) | ||||
| 		decoder := fieldDecoders[fieldCacheKey] | ||||
| 		if decoder == nil { | ||||
| 			var err error | ||||
| 			decoder, err = decoderOfType(cfg, field.Type) | ||||
| 			if len(fieldNames) > 0 && err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			decoder = decoderOfType(cfg, prefix+typ.String()+"."+field.Name+"->", field.Type) | ||||
| 		} | ||||
| 		encoder := fieldEncoders[fieldCacheKey] | ||||
| 		if encoder == nil { | ||||
| 			var err error | ||||
| 			encoder, err = encoderOfType(cfg, field.Type) | ||||
| 			if len(fieldNames) > 0 && err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			encoder = encoderOfType(cfg, prefix+typ.String()+"."+field.Name+"->", field.Type) | ||||
| 			// map is stored as pointer in the struct, | ||||
| 			// and treat nil or empty map as empty field | ||||
| 			if encoder != nil && field.Type.Kind() == reflect.Map { | ||||
| @@ -314,7 +300,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err | ||||
| 		binding.levels = []int{i} | ||||
| 		bindings = append(bindings, binding) | ||||
| 	} | ||||
| 	return createStructDescriptor(cfg, typ, bindings, embeddedBindings), nil | ||||
| 	return createStructDescriptor(cfg, typ, bindings, embeddedBindings) | ||||
| } | ||||
| func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { | ||||
| 	onePtrEmbedded := false | ||||
|   | ||||
| @@ -9,6 +9,22 @@ import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| func decoderOfMap(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { | ||||
| 	decoder := decoderOfType(cfg, prefix+"[map]->", typ.Elem()) | ||||
| 	mapInterface := reflect.New(typ).Interface() | ||||
| 	return &mapDecoder{typ, typ.Key(), typ.Elem(), decoder, extractInterface(mapInterface)} | ||||
| } | ||||
|  | ||||
| func encoderOfMap(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { | ||||
| 	elemType := typ.Elem() | ||||
| 	encoder := encoderOfType(cfg, prefix+"[map]->", elemType) | ||||
| 	mapInterface := reflect.New(typ).Elem().Interface() | ||||
| 	if cfg.sortMapKeys { | ||||
| 		return &sortKeysMapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))} | ||||
| 	} | ||||
| 	return &mapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))} | ||||
| } | ||||
|  | ||||
| type mapDecoder struct { | ||||
| 	mapType      reflect.Type | ||||
| 	keyType      reflect.Type | ||||
|   | ||||
| @@ -8,17 +8,14 @@ import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { | ||||
| func encoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { | ||||
| 	type bindingTo struct { | ||||
| 		binding *Binding | ||||
| 		toName  string | ||||
| 		ignored bool | ||||
| 	} | ||||
| 	orderedBindings := []*bindingTo{} | ||||
| 	structDescriptor, err := describeStruct(cfg, typ) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	structDescriptor := describeStruct(cfg, prefix, typ) | ||||
| 	for _, binding := range structDescriptor.Fields { | ||||
| 		for _, toName := range binding.ToNames { | ||||
| 			new := &bindingTo{ | ||||
| @@ -35,7 +32,7 @@ func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { | ||||
| 		} | ||||
| 	} | ||||
| 	if len(orderedBindings) == 0 { | ||||
| 		return &emptyStructEncoder{}, nil | ||||
| 		return &emptyStructEncoder{} | ||||
| 	} | ||||
| 	finalOrderedFields := []structFieldTo{} | ||||
| 	for _, bindingTo := range orderedBindings { | ||||
| @@ -46,7 +43,8 @@ func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| 	return &structEncoder{structDescriptor.onePtrEmbedded, structDescriptor.onePtrOptimization, finalOrderedFields}, nil | ||||
| 	return &structEncoder{typ, structDescriptor.onePtrEmbedded, | ||||
| 		structDescriptor.onePtrOptimization, finalOrderedFields} | ||||
| } | ||||
|  | ||||
| func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) { | ||||
| @@ -78,12 +76,9 @@ func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ig | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func decoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { | ||||
| func decoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { | ||||
| 	bindings := map[string]*Binding{} | ||||
| 	structDescriptor, err := describeStruct(cfg, typ) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	structDescriptor := describeStruct(cfg, prefix, typ) | ||||
| 	for _, binding := range structDescriptor.Fields { | ||||
| 		for _, fromName := range binding.FromNames { | ||||
| 			old := bindings[fromName] | ||||
| @@ -131,6 +126,7 @@ func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { | ||||
| } | ||||
|  | ||||
| type structEncoder struct { | ||||
| 	typ                reflect.Type | ||||
| 	onePtrEmbedded     bool | ||||
| 	onePtrOptimization bool | ||||
| 	fields             []structFieldTo | ||||
| @@ -156,6 +152,9 @@ func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { | ||||
| 		isNotFirst = true | ||||
| 	} | ||||
| 	stream.WriteObjectEnd() | ||||
| 	if stream.Error != nil && stream.Error != io.EOF { | ||||
| 		stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (encoder *structEncoder) EncodeInterface(val interface{}, stream *Stream) { | ||||
|   | ||||
							
								
								
									
										104
									
								
								feature_reflect_optional.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								feature_reflect_optional.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| package jsoniter | ||||
|  | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| func decoderOfOptional(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { | ||||
| 	elemType := typ.Elem() | ||||
| 	decoder := decoderOfType(cfg, prefix, elemType) | ||||
| 	return &OptionalDecoder{elemType, decoder} | ||||
| } | ||||
|  | ||||
| func encoderOfOptional(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { | ||||
| 	elemType := typ.Elem() | ||||
| 	elemEncoder := encoderOfType(cfg, prefix, elemType) | ||||
| 	encoder := &OptionalEncoder{elemEncoder} | ||||
| 	if elemType.Kind() == reflect.Map { | ||||
| 		encoder = &OptionalEncoder{encoder} | ||||
| 	} | ||||
| 	return encoder | ||||
| } | ||||
|  | ||||
| type OptionalDecoder struct { | ||||
| 	ValueType    reflect.Type | ||||
| 	ValueDecoder ValDecoder | ||||
| } | ||||
|  | ||||
| func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { | ||||
| 	if iter.ReadNil() { | ||||
| 		*((*unsafe.Pointer)(ptr)) = nil | ||||
| 	} else { | ||||
| 		if *((*unsafe.Pointer)(ptr)) == nil { | ||||
| 			//pointer to null, we have to allocate memory to hold the value | ||||
| 			value := reflect.New(decoder.ValueType) | ||||
| 			newPtr := extractInterface(value.Interface()).word | ||||
| 			decoder.ValueDecoder.Decode(newPtr, iter) | ||||
| 			*((*uintptr)(ptr)) = uintptr(newPtr) | ||||
| 		} else { | ||||
| 			//reuse existing instance | ||||
| 			decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type deferenceDecoder struct { | ||||
| 	// only to deference a pointer | ||||
| 	valueType    reflect.Type | ||||
| 	valueDecoder ValDecoder | ||||
| } | ||||
|  | ||||
| func (decoder *deferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { | ||||
| 	if *((*unsafe.Pointer)(ptr)) == nil { | ||||
| 		//pointer to null, we have to allocate memory to hold the value | ||||
| 		value := reflect.New(decoder.valueType) | ||||
| 		newPtr := extractInterface(value.Interface()).word | ||||
| 		decoder.valueDecoder.Decode(newPtr, iter) | ||||
| 		*((*uintptr)(ptr)) = uintptr(newPtr) | ||||
| 	} else { | ||||
| 		//reuse existing instance | ||||
| 		decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type OptionalEncoder struct { | ||||
| 	ValueEncoder ValEncoder | ||||
| } | ||||
|  | ||||
| func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { | ||||
| 	if *((*unsafe.Pointer)(ptr)) == nil { | ||||
| 		stream.WriteNil() | ||||
| 	} else { | ||||
| 		encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (encoder *OptionalEncoder) EncodeInterface(val interface{}, stream *Stream) { | ||||
| 	WriteToStream(val, stream, encoder) | ||||
| } | ||||
|  | ||||
| func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { | ||||
| 	return *((*unsafe.Pointer)(ptr)) == nil | ||||
| } | ||||
|  | ||||
| type optionalMapEncoder struct { | ||||
| 	valueEncoder ValEncoder | ||||
| } | ||||
|  | ||||
| func (encoder *optionalMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { | ||||
| 	if *((*unsafe.Pointer)(ptr)) == nil { | ||||
| 		stream.WriteNil() | ||||
| 	} else { | ||||
| 		encoder.valueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (encoder *optionalMapEncoder) EncodeInterface(val interface{}, stream *Stream) { | ||||
| 	WriteToStream(val, stream, encoder) | ||||
| } | ||||
|  | ||||
| func (encoder *optionalMapEncoder) IsEmpty(ptr unsafe.Pointer) bool { | ||||
| 	p := *((*unsafe.Pointer)(ptr)) | ||||
| 	return p == nil || encoder.valueEncoder.IsEmpty(p) | ||||
| } | ||||
| @@ -7,23 +7,17 @@ import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| func decoderOfSlice(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { | ||||
| 	decoder, err := decoderOfType(cfg, typ.Elem()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &sliceDecoder{typ, typ.Elem(), decoder}, nil | ||||
| func decoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { | ||||
| 	decoder := decoderOfType(cfg, prefix+"[slice]->", typ.Elem()) | ||||
| 	return &sliceDecoder{typ, typ.Elem(), decoder} | ||||
| } | ||||
|  | ||||
| func encoderOfSlice(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { | ||||
| 	encoder, err := encoderOfType(cfg, typ.Elem()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| func encoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { | ||||
| 	encoder := encoderOfType(cfg, prefix+"[slice]->", typ.Elem()) | ||||
| 	if typ.Elem().Kind() == reflect.Map { | ||||
| 		encoder = &OptionalEncoder{encoder} | ||||
| 	} | ||||
| 	return &sliceEncoder{typ, typ.Elem(), encoder}, nil | ||||
| 	return &sliceEncoder{typ, typ.Elem(), encoder} | ||||
| } | ||||
|  | ||||
| type sliceEncoder struct { | ||||
|   | ||||
| @@ -8,22 +8,22 @@ import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder) (ValDecoder, error) { | ||||
| func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder) ValDecoder { | ||||
| 	knownHash := map[int32]struct{}{ | ||||
| 		0: {}, | ||||
| 	} | ||||
| 	switch len(fields) { | ||||
| 	case 0: | ||||
| 		return &skipObjectDecoder{typ}, nil | ||||
| 		return &skipObjectDecoder{typ} | ||||
| 	case 1: | ||||
| 		for fieldName, fieldDecoder := range fields { | ||||
| 			fieldHash := calcHash(fieldName) | ||||
| 			_, known := knownHash[fieldHash] | ||||
| 			if known { | ||||
| 				return &generalStructDecoder{typ, fields}, nil | ||||
| 				return &generalStructDecoder{typ, fields} | ||||
| 			} | ||||
| 			knownHash[fieldHash] = struct{}{} | ||||
| 			return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder}, nil | ||||
| 			return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder} | ||||
| 		} | ||||
| 	case 2: | ||||
| 		var fieldHash1 int32 | ||||
| @@ -34,7 +34,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			fieldHash := calcHash(fieldName) | ||||
| 			_, known := knownHash[fieldHash] | ||||
| 			if known { | ||||
| 				return &generalStructDecoder{typ, fields}, nil | ||||
| 				return &generalStructDecoder{typ, fields} | ||||
| 			} | ||||
| 			knownHash[fieldHash] = struct{}{} | ||||
| 			if fieldHash1 == 0 { | ||||
| @@ -45,7 +45,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 				fieldDecoder2 = fieldDecoder | ||||
| 			} | ||||
| 		} | ||||
| 		return &twoFieldsStructDecoder{typ, fieldHash1, fieldDecoder1, fieldHash2, fieldDecoder2}, nil | ||||
| 		return &twoFieldsStructDecoder{typ, fieldHash1, fieldDecoder1, fieldHash2, fieldDecoder2} | ||||
| 	case 3: | ||||
| 		var fieldName1 int32 | ||||
| 		var fieldName2 int32 | ||||
| @@ -57,7 +57,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			fieldHash := calcHash(fieldName) | ||||
| 			_, known := knownHash[fieldHash] | ||||
| 			if known { | ||||
| 				return &generalStructDecoder{typ, fields}, nil | ||||
| 				return &generalStructDecoder{typ, fields} | ||||
| 			} | ||||
| 			knownHash[fieldHash] = struct{}{} | ||||
| 			if fieldName1 == 0 { | ||||
| @@ -72,7 +72,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			} | ||||
| 		} | ||||
| 		return &threeFieldsStructDecoder{typ, | ||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil | ||||
| 			fieldName1, fieldDecoder1, | ||||
| 			fieldName2, fieldDecoder2, | ||||
| 			fieldName3, fieldDecoder3} | ||||
| 	case 4: | ||||
| 		var fieldName1 int32 | ||||
| 		var fieldName2 int32 | ||||
| @@ -86,7 +88,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			fieldHash := calcHash(fieldName) | ||||
| 			_, known := knownHash[fieldHash] | ||||
| 			if known { | ||||
| 				return &generalStructDecoder{typ, fields}, nil | ||||
| 				return &generalStructDecoder{typ, fields} | ||||
| 			} | ||||
| 			knownHash[fieldHash] = struct{}{} | ||||
| 			if fieldName1 == 0 { | ||||
| @@ -104,8 +106,10 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			} | ||||
| 		} | ||||
| 		return &fourFieldsStructDecoder{typ, | ||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4}, nil | ||||
| 			fieldName1, fieldDecoder1, | ||||
| 			fieldName2, fieldDecoder2, | ||||
| 			fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4} | ||||
| 	case 5: | ||||
| 		var fieldName1 int32 | ||||
| 		var fieldName2 int32 | ||||
| @@ -121,7 +125,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			fieldHash := calcHash(fieldName) | ||||
| 			_, known := knownHash[fieldHash] | ||||
| 			if known { | ||||
| 				return &generalStructDecoder{typ, fields}, nil | ||||
| 				return &generalStructDecoder{typ, fields} | ||||
| 			} | ||||
| 			knownHash[fieldHash] = struct{}{} | ||||
| 			if fieldName1 == 0 { | ||||
| @@ -142,8 +146,11 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			} | ||||
| 		} | ||||
| 		return &fiveFieldsStructDecoder{typ, | ||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil | ||||
| 			fieldName1, fieldDecoder1, | ||||
| 			fieldName2, fieldDecoder2, | ||||
| 			fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, | ||||
| 			fieldName5, fieldDecoder5} | ||||
| 	case 6: | ||||
| 		var fieldName1 int32 | ||||
| 		var fieldName2 int32 | ||||
| @@ -161,7 +168,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			fieldHash := calcHash(fieldName) | ||||
| 			_, known := knownHash[fieldHash] | ||||
| 			if known { | ||||
| 				return &generalStructDecoder{typ, fields}, nil | ||||
| 				return &generalStructDecoder{typ, fields} | ||||
| 			} | ||||
| 			knownHash[fieldHash] = struct{}{} | ||||
| 			if fieldName1 == 0 { | ||||
| @@ -185,8 +192,12 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			} | ||||
| 		} | ||||
| 		return &sixFieldsStructDecoder{typ, | ||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil | ||||
| 			fieldName1, fieldDecoder1, | ||||
| 			fieldName2, fieldDecoder2, | ||||
| 			fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, | ||||
| 			fieldName5, fieldDecoder5, | ||||
| 			fieldName6, fieldDecoder6} | ||||
| 	case 7: | ||||
| 		var fieldName1 int32 | ||||
| 		var fieldName2 int32 | ||||
| @@ -206,7 +217,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			fieldHash := calcHash(fieldName) | ||||
| 			_, known := knownHash[fieldHash] | ||||
| 			if known { | ||||
| 				return &generalStructDecoder{typ, fields}, nil | ||||
| 				return &generalStructDecoder{typ, fields} | ||||
| 			} | ||||
| 			knownHash[fieldHash] = struct{}{} | ||||
| 			if fieldName1 == 0 { | ||||
| @@ -233,9 +244,13 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			} | ||||
| 		} | ||||
| 		return &sevenFieldsStructDecoder{typ, | ||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | ||||
| 			fieldName7, fieldDecoder7}, nil | ||||
| 			fieldName1, fieldDecoder1, | ||||
| 			fieldName2, fieldDecoder2, | ||||
| 			fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, | ||||
| 			fieldName5, fieldDecoder5, | ||||
| 			fieldName6, fieldDecoder6, | ||||
| 			fieldName7, fieldDecoder7} | ||||
| 	case 8: | ||||
| 		var fieldName1 int32 | ||||
| 		var fieldName2 int32 | ||||
| @@ -257,7 +272,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			fieldHash := calcHash(fieldName) | ||||
| 			_, known := knownHash[fieldHash] | ||||
| 			if known { | ||||
| 				return &generalStructDecoder{typ, fields}, nil | ||||
| 				return &generalStructDecoder{typ, fields} | ||||
| 			} | ||||
| 			knownHash[fieldHash] = struct{}{} | ||||
| 			if fieldName1 == 0 { | ||||
| @@ -287,9 +302,14 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			} | ||||
| 		} | ||||
| 		return &eightFieldsStructDecoder{typ, | ||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | ||||
| 			fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil | ||||
| 			fieldName1, fieldDecoder1, | ||||
| 			fieldName2, fieldDecoder2, | ||||
| 			fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, | ||||
| 			fieldName5, fieldDecoder5, | ||||
| 			fieldName6, fieldDecoder6, | ||||
| 			fieldName7, fieldDecoder7, | ||||
| 			fieldName8, fieldDecoder8} | ||||
| 	case 9: | ||||
| 		var fieldName1 int32 | ||||
| 		var fieldName2 int32 | ||||
| @@ -313,7 +333,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			fieldHash := calcHash(fieldName) | ||||
| 			_, known := knownHash[fieldHash] | ||||
| 			if known { | ||||
| 				return &generalStructDecoder{typ, fields}, nil | ||||
| 				return &generalStructDecoder{typ, fields} | ||||
| 			} | ||||
| 			knownHash[fieldHash] = struct{}{} | ||||
| 			if fieldName1 == 0 { | ||||
| @@ -346,9 +366,15 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			} | ||||
| 		} | ||||
| 		return &nineFieldsStructDecoder{typ, | ||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | ||||
| 			fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil | ||||
| 			fieldName1, fieldDecoder1, | ||||
| 			fieldName2, fieldDecoder2, | ||||
| 			fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, | ||||
| 			fieldName5, fieldDecoder5, | ||||
| 			fieldName6, fieldDecoder6, | ||||
| 			fieldName7, fieldDecoder7, | ||||
| 			fieldName8, fieldDecoder8, | ||||
| 			fieldName9, fieldDecoder9} | ||||
| 	case 10: | ||||
| 		var fieldName1 int32 | ||||
| 		var fieldName2 int32 | ||||
| @@ -374,7 +400,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			fieldHash := calcHash(fieldName) | ||||
| 			_, known := knownHash[fieldHash] | ||||
| 			if known { | ||||
| 				return &generalStructDecoder{typ, fields}, nil | ||||
| 				return &generalStructDecoder{typ, fields} | ||||
| 			} | ||||
| 			knownHash[fieldHash] = struct{}{} | ||||
| 			if fieldName1 == 0 { | ||||
| @@ -410,12 +436,18 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | ||||
| 			} | ||||
| 		} | ||||
| 		return &tenFieldsStructDecoder{typ, | ||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | ||||
| 			fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9, | ||||
| 			fieldName10, fieldDecoder10}, nil | ||||
| 			fieldName1, fieldDecoder1, | ||||
| 			fieldName2, fieldDecoder2, | ||||
| 			fieldName3, fieldDecoder3, | ||||
| 			fieldName4, fieldDecoder4, | ||||
| 			fieldName5, fieldDecoder5, | ||||
| 			fieldName6, fieldDecoder6, | ||||
| 			fieldName7, fieldDecoder7, | ||||
| 			fieldName8, fieldDecoder8, | ||||
| 			fieldName9, fieldDecoder9, | ||||
| 			fieldName10, fieldDecoder10} | ||||
| 	} | ||||
| 	return &generalStructDecoder{typ, fields}, nil | ||||
| 	return &generalStructDecoder{typ, fields} | ||||
| } | ||||
|  | ||||
| type generalStructDecoder struct { | ||||
| @@ -464,7 +496,7 @@ func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -502,7 +534,7 @@ func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -532,7 +564,7 @@ func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -566,7 +598,7 @@ func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -604,7 +636,7 @@ func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -646,7 +678,7 @@ func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -692,7 +724,7 @@ func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -742,7 +774,7 @@ func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -796,7 +828,7 @@ func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -854,7 +886,7 @@ func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -916,7 +948,7 @@ func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator | ||||
| 		} | ||||
| 	} | ||||
| 	if iter.Error != nil && iter.Error != io.EOF { | ||||
| 		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error()) | ||||
| 		iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -109,12 +109,13 @@ func (extension *testExtension) UpdateStructDescriptor(structDescriptor *StructD | ||||
|  | ||||
| func Test_customize_field_by_extension(t *testing.T) { | ||||
| 	should := require.New(t) | ||||
| 	RegisterExtension(&testExtension{}) | ||||
| 	cfg := Config{}.Froze() | ||||
| 	cfg.RegisterExtension(&testExtension{}) | ||||
| 	obj := TestObject1{} | ||||
| 	err := UnmarshalFromString(`{"field-1": 100}`, &obj) | ||||
| 	err := cfg.UnmarshalFromString(`{"field-1": 100}`, &obj) | ||||
| 	should.Nil(err) | ||||
| 	should.Equal("100", obj.Field1) | ||||
| 	str, err := MarshalToString(obj) | ||||
| 	str, err := cfg.MarshalToString(obj) | ||||
| 	should.Nil(err) | ||||
| 	should.Equal(`{"field-1":100}`, str) | ||||
| } | ||||
|   | ||||
| @@ -20,7 +20,7 @@ func Test_write_empty_interface_via_placeholder(t *testing.T) { | ||||
| 		cacheKey: reflect.TypeOf(m).Elem(), | ||||
| 	} | ||||
| 	stream := ConfigFastest.BorrowStream(nil) | ||||
| 	encoderOfType(ConfigFastest.(*frozenConfig), reflect.TypeOf(m).Elem()) | ||||
| 	encoderOfType(ConfigFastest.(*frozenConfig), "", reflect.TypeOf(m).Elem()) | ||||
| 	encoder.EncodeInterface(inf, stream) | ||||
| 	should.Equal(`"hello"`, string(stream.Buffer())) | ||||
| } | ||||
|   | ||||
| @@ -147,3 +147,40 @@ func Test_nil_pointer(t *testing.T) { | ||||
| 	err := Unmarshal(data, obj) | ||||
| 	should.NotNil(err) | ||||
| } | ||||
|  | ||||
| func Test_func_pointer_type(t *testing.T) { | ||||
| 	type TestObject2 struct { | ||||
| 		F func() | ||||
| 	} | ||||
| 	type TestObject1 struct { | ||||
| 		Obj *TestObject2 | ||||
| 	} | ||||
| 	t.Run("encode null is valid", func(t *testing.T) { | ||||
| 		should := require.New(t) | ||||
| 		output, err := json.Marshal(TestObject1{}) | ||||
| 		should.Nil(err) | ||||
| 		should.Equal(`{"Obj":null}`, string(output)) | ||||
| 		output, err = Marshal(TestObject1{}) | ||||
| 		should.Nil(err) | ||||
| 		should.Equal(`{"Obj":null}`, string(output)) | ||||
| 	}) | ||||
| 	t.Run("encode not null is invalid", func(t *testing.T) { | ||||
| 		should := require.New(t) | ||||
| 		_, err := json.Marshal(TestObject1{Obj: &TestObject2{}}) | ||||
| 		should.NotNil(err) | ||||
| 		_, err = Marshal(TestObject1{Obj: &TestObject2{}}) | ||||
| 		should.NotNil(err) | ||||
| 	}) | ||||
| 	t.Run("decode null is valid", func(t *testing.T) { | ||||
| 		should := require.New(t) | ||||
| 		var obj TestObject1 | ||||
| 		should.Nil(json.Unmarshal([]byte(`{"Obj":{"F": null}}`), &obj)) | ||||
| 		should.Nil(Unmarshal([]byte(`{"Obj":{"F": null}}`), &obj)) | ||||
| 	}) | ||||
| 	t.Run("decode not null is invalid", func(t *testing.T) { | ||||
| 		should := require.New(t) | ||||
| 		var obj TestObject1 | ||||
| 		should.NotNil(json.Unmarshal([]byte(`{"Obj":{"F": "hello"}}`), &obj)) | ||||
| 		should.NotNil(Unmarshal([]byte(`{"Obj":{"F": "hello"}}`), &obj)) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user