github.com/zerosnake0/jzon@v0.0.9-0.20230801092939-1b135cb83f7f/val_encoder_native_struct.go (about)

     1  package jzon
     2  
     3  import (
     4  	"reflect"
     5  	"unsafe"
     6  )
     7  
     8  type structEncoderBuilder struct {
     9  	encoder *structEncoder
    10  	fields  structFields
    11  }
    12  
    13  func (encCfg *EncoderConfig) newStructEncoder(typ reflect.Type) *structEncoderBuilder {
    14  	fields := describeStruct(typ, encCfg.tag, encCfg.onlyTaggedField)
    15  	if len(fields) == 0 {
    16  		return nil
    17  	}
    18  	return &structEncoderBuilder{
    19  		encoder: &structEncoder{},
    20  		fields:  fields,
    21  	}
    22  }
    23  
    24  // encoder field info
    25  type encoderFieldInfo struct {
    26  	offsets      []uintptr
    27  	rawField     []byte
    28  	safeRawField []byte
    29  	quoted       bool
    30  	omitEmpty    bool
    31  	encoder      ValEncoder
    32  }
    33  
    34  type encoderFields struct {
    35  	list []encoderFieldInfo
    36  }
    37  
    38  func (ef *encoderFields) init(size int) {
    39  	ef.list = make([]encoderFieldInfo, 0, size)
    40  }
    41  
    42  func (ef *encoderFields) add(f *field, enc ValEncoder) {
    43  	safeRawField := encodeString(nil, f.name, htmlSafeSet[:])
    44  	rawField := encodeString(nil, f.name, safeSet[:])
    45  	offsets := make([]uintptr, len(f.offsets))
    46  	for i := range f.offsets {
    47  		offsets[i] = f.offsets[i].val
    48  	}
    49  	ef.list = append(ef.list, encoderFieldInfo{
    50  		offsets:      offsets,
    51  		rawField:     rawField,
    52  		safeRawField: safeRawField,
    53  		quoted:       f.quoted,
    54  		omitEmpty:    f.omitEmpty,
    55  		encoder:      enc,
    56  	})
    57  }
    58  
    59  // struct encoder
    60  type structEncoder struct {
    61  	fields encoderFields
    62  }
    63  
    64  func (enc *structEncoder) IsEmpty(ptr unsafe.Pointer) bool {
    65  	return false
    66  }
    67  
    68  func (enc *structEncoder) Encode(ptr unsafe.Pointer, s *Streamer, opts *EncOpts) {
    69  	if s.Error != nil {
    70  		return
    71  	}
    72  	if ptr == nil {
    73  		s.Null()
    74  		return
    75  	}
    76  	s.ObjectStart()
    77  OuterLoop:
    78  	for i := range enc.fields.list {
    79  		fi := &enc.fields.list[i]
    80  		curPtr := add(ptr, fi.offsets[0], "struct field")
    81  		// ptr != nil => curPtr != nil
    82  		for _, offset := range fi.offsets[1:] {
    83  			curPtr = *(*unsafe.Pointer)(curPtr)
    84  			if curPtr == nil {
    85  				// the embedded pointer field is nil
    86  				continue OuterLoop
    87  			}
    88  			curPtr = add(curPtr, offset, "struct field")
    89  		}
    90  		if fi.omitEmpty {
    91  			if fi.encoder.IsEmpty(curPtr) {
    92  				continue
    93  			}
    94  		}
    95  		if s.escapeHTML {
    96  			s.RawField(fi.safeRawField)
    97  		} else {
    98  			s.RawField(fi.rawField)
    99  		}
   100  		opt := EncOpts{
   101  			Quoted: fi.quoted,
   102  		}
   103  		fi.encoder.Encode(curPtr, s, opt.noescape())
   104  		if s.Error != nil {
   105  			return
   106  		}
   107  	}
   108  	s.ObjectEnd()
   109  }
   110  
   111  // no fields to encoder
   112  type emptyStructEncoder struct{}
   113  
   114  func (*emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool {
   115  	return true
   116  }
   117  
   118  func (*emptyStructEncoder) Encode(ptr unsafe.Pointer, s *Streamer, opts *EncOpts) {
   119  	if ptr == nil {
   120  		s.Null()
   121  		return
   122  	}
   123  	s.RawString("{}")
   124  }