...

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

Documentation: github.com/json-iterator/go

     1  package jsoniter
     2  
     3  import (
     4  	"encoding"
     5  	"encoding/json"
     6  	"unsafe"
     7  
     8  	"github.com/modern-go/reflect2"
     9  )
    10  
    11  var marshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem()
    12  var unmarshalerType = reflect2.TypeOfPtr((*json.Unmarshaler)(nil)).Elem()
    13  var textMarshalerType = reflect2.TypeOfPtr((*encoding.TextMarshaler)(nil)).Elem()
    14  var textUnmarshalerType = reflect2.TypeOfPtr((*encoding.TextUnmarshaler)(nil)).Elem()
    15  
    16  func createDecoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValDecoder {
    17  	ptrType := reflect2.PtrTo(typ)
    18  	if ptrType.Implements(unmarshalerType) {
    19  		return &referenceDecoder{
    20  			&unmarshalerDecoder{ptrType},
    21  		}
    22  	}
    23  	if ptrType.Implements(textUnmarshalerType) {
    24  		return &referenceDecoder{
    25  			&textUnmarshalerDecoder{ptrType},
    26  		}
    27  	}
    28  	return nil
    29  }
    30  
    31  func createEncoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValEncoder {
    32  	if typ == marshalerType {
    33  		checkIsEmpty := createCheckIsEmpty(ctx, typ)
    34  		var encoder ValEncoder = &directMarshalerEncoder{
    35  			checkIsEmpty: checkIsEmpty,
    36  		}
    37  		return encoder
    38  	}
    39  	if typ.Implements(marshalerType) {
    40  		checkIsEmpty := createCheckIsEmpty(ctx, typ)
    41  		var encoder ValEncoder = &marshalerEncoder{
    42  			valType:      typ,
    43  			checkIsEmpty: checkIsEmpty,
    44  		}
    45  		return encoder
    46  	}
    47  	ptrType := reflect2.PtrTo(typ)
    48  	if ctx.prefix != "" && ptrType.Implements(marshalerType) {
    49  		checkIsEmpty := createCheckIsEmpty(ctx, ptrType)
    50  		var encoder ValEncoder = &marshalerEncoder{
    51  			valType:      ptrType,
    52  			checkIsEmpty: checkIsEmpty,
    53  		}
    54  		return &referenceEncoder{encoder}
    55  	}
    56  	if typ == textMarshalerType {
    57  		checkIsEmpty := createCheckIsEmpty(ctx, typ)
    58  		var encoder ValEncoder = &directTextMarshalerEncoder{
    59  			checkIsEmpty:  checkIsEmpty,
    60  			stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
    61  		}
    62  		return encoder
    63  	}
    64  	if typ.Implements(textMarshalerType) {
    65  		checkIsEmpty := createCheckIsEmpty(ctx, typ)
    66  		var encoder ValEncoder = &textMarshalerEncoder{
    67  			valType:       typ,
    68  			stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
    69  			checkIsEmpty:  checkIsEmpty,
    70  		}
    71  		return encoder
    72  	}
    73  	// if prefix is empty, the type is the root type
    74  	if ctx.prefix != "" && ptrType.Implements(textMarshalerType) {
    75  		checkIsEmpty := createCheckIsEmpty(ctx, ptrType)
    76  		var encoder ValEncoder = &textMarshalerEncoder{
    77  			valType:       ptrType,
    78  			stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
    79  			checkIsEmpty:  checkIsEmpty,
    80  		}
    81  		return &referenceEncoder{encoder}
    82  	}
    83  	return nil
    84  }
    85  
    86  type marshalerEncoder struct {
    87  	checkIsEmpty checkIsEmpty
    88  	valType      reflect2.Type
    89  }
    90  
    91  func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
    92  	obj := encoder.valType.UnsafeIndirect(ptr)
    93  	if encoder.valType.IsNullable() && reflect2.IsNil(obj) {
    94  		stream.WriteNil()
    95  		return
    96  	}
    97  	marshaler := obj.(json.Marshaler)
    98  	bytes, err := marshaler.MarshalJSON()
    99  	if err != nil {
   100  		stream.Error = err
   101  	} else {
   102  		// html escape was already done by jsoniter
   103  		// but the extra '\n' should be trimed
   104  		l := len(bytes)
   105  		if l > 0 && bytes[l-1] == '\n' {
   106  			bytes = bytes[:l-1]
   107  		}
   108  		stream.Write(bytes)
   109  	}
   110  }
   111  
   112  func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
   113  	return encoder.checkIsEmpty.IsEmpty(ptr)
   114  }
   115  
   116  type directMarshalerEncoder struct {
   117  	checkIsEmpty checkIsEmpty
   118  }
   119  
   120  func (encoder *directMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
   121  	marshaler := *(*json.Marshaler)(ptr)
   122  	if marshaler == nil {
   123  		stream.WriteNil()
   124  		return
   125  	}
   126  	bytes, err := marshaler.MarshalJSON()
   127  	if err != nil {
   128  		stream.Error = err
   129  	} else {
   130  		stream.Write(bytes)
   131  	}
   132  }
   133  
   134  func (encoder *directMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
   135  	return encoder.checkIsEmpty.IsEmpty(ptr)
   136  }
   137  
   138  type textMarshalerEncoder struct {
   139  	valType       reflect2.Type
   140  	stringEncoder ValEncoder
   141  	checkIsEmpty  checkIsEmpty
   142  }
   143  
   144  func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
   145  	obj := encoder.valType.UnsafeIndirect(ptr)
   146  	if encoder.valType.IsNullable() && reflect2.IsNil(obj) {
   147  		stream.WriteNil()
   148  		return
   149  	}
   150  	marshaler := (obj).(encoding.TextMarshaler)
   151  	bytes, err := marshaler.MarshalText()
   152  	if err != nil {
   153  		stream.Error = err
   154  	} else {
   155  		str := string(bytes)
   156  		encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream)
   157  	}
   158  }
   159  
   160  func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
   161  	return encoder.checkIsEmpty.IsEmpty(ptr)
   162  }
   163  
   164  type directTextMarshalerEncoder struct {
   165  	stringEncoder ValEncoder
   166  	checkIsEmpty  checkIsEmpty
   167  }
   168  
   169  func (encoder *directTextMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
   170  	marshaler := *(*encoding.TextMarshaler)(ptr)
   171  	if marshaler == nil {
   172  		stream.WriteNil()
   173  		return
   174  	}
   175  	bytes, err := marshaler.MarshalText()
   176  	if err != nil {
   177  		stream.Error = err
   178  	} else {
   179  		str := string(bytes)
   180  		encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream)
   181  	}
   182  }
   183  
   184  func (encoder *directTextMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
   185  	return encoder.checkIsEmpty.IsEmpty(ptr)
   186  }
   187  
   188  type unmarshalerDecoder struct {
   189  	valType reflect2.Type
   190  }
   191  
   192  func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
   193  	valType := decoder.valType
   194  	obj := valType.UnsafeIndirect(ptr)
   195  	unmarshaler := obj.(json.Unmarshaler)
   196  	iter.nextToken()
   197  	iter.unreadByte() // skip spaces
   198  	bytes := iter.SkipAndReturnBytes()
   199  	err := unmarshaler.UnmarshalJSON(bytes)
   200  	if err != nil {
   201  		iter.ReportError("unmarshalerDecoder", err.Error())
   202  	}
   203  }
   204  
   205  type textUnmarshalerDecoder struct {
   206  	valType reflect2.Type
   207  }
   208  
   209  func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
   210  	valType := decoder.valType
   211  	obj := valType.UnsafeIndirect(ptr)
   212  	if reflect2.IsNil(obj) {
   213  		ptrType := valType.(*reflect2.UnsafePtrType)
   214  		elemType := ptrType.Elem()
   215  		elem := elemType.UnsafeNew()
   216  		ptrType.UnsafeSet(ptr, unsafe.Pointer(&elem))
   217  		obj = valType.UnsafeIndirect(ptr)
   218  	}
   219  	unmarshaler := (obj).(encoding.TextUnmarshaler)
   220  	str := iter.ReadString()
   221  	err := unmarshaler.UnmarshalText([]byte(str))
   222  	if err != nil {
   223  		iter.ReportError("textUnmarshalerDecoder", err.Error())
   224  	}
   225  }
   226  

View as plain text