WriteRefOrNull write reference and tag for the value if the value has been written previously, write null/not-null tag otherwise. Returns true if no bytes need to be written for the object. See https://go101.org/article/value-part.html for internal structure definitions of common types. Note that fo
(buffer *ByteBuffer, value reflect.Value)
| 129 | // Note that for slice and substring, if the start addr or length are different, we take two objects as |
| 130 | // different references. |
| 131 | func (r *RefResolver) WriteRefOrNull(buffer *ByteBuffer, value reflect.Value) (refWritten bool, err error) { |
| 132 | if !r.refTracking || value.Kind() == reflect.String { |
| 133 | if isNil(value) { |
| 134 | buffer.WriteInt8(NullFlag) |
| 135 | return true, nil |
| 136 | } else { |
| 137 | buffer.WriteInt8(NotNullValueFlag) |
| 138 | return false, nil |
| 139 | } |
| 140 | } |
| 141 | length := 0 |
| 142 | isNil := false |
| 143 | kind := value.Kind() |
| 144 | // reference types such as channel/function are not handled here and will be handled by typeResolver. |
| 145 | switch kind { |
| 146 | case reflect.Ptr: |
| 147 | elemValue := value.Elem() |
| 148 | if elemValue.Kind() == reflect.Array { |
| 149 | length = elemValue.Len() |
| 150 | } |
| 151 | isNil = value.IsNil() |
| 152 | case reflect.Map: |
| 153 | isNil = value.IsNil() |
| 154 | case reflect.Slice: |
| 155 | isNil = value.IsNil() |
| 156 | length = value.Len() |
| 157 | case reflect.Interface: |
| 158 | value = value.Elem() |
| 159 | return r.WriteRefOrNull(buffer, value) |
| 160 | case reflect.Invalid: |
| 161 | isNil = true |
| 162 | case reflect.Struct: |
| 163 | // Struct values are value types, not reference types. |
| 164 | // They should not participate in reference tracking. |
| 165 | buffer.WriteInt8(NotNullValueFlag) |
| 166 | return false, nil |
| 167 | default: |
| 168 | // The object is being written for the first time. |
| 169 | buffer.WriteInt8(NotNullValueFlag) |
| 170 | return false, nil |
| 171 | } |
| 172 | if isNil { |
| 173 | buffer.WriteInt8(NullFlag) |
| 174 | return true, nil |
| 175 | } else { |
| 176 | refKey := refKey{pointer: unsafe.Pointer(value.Pointer()), length: length} |
| 177 | if writtenId, ok := r.writtenObjects[refKey]; ok { |
| 178 | // The obj has been written previously. |
| 179 | buffer.WriteInt8(RefFlag) |
| 180 | buffer.WriteVarUint32(uint32(writtenId)) |
| 181 | return true, nil |
| 182 | } else { |
| 183 | // The id should be consistent with `nextReadRefId` |
| 184 | newWriteRefId := len(r.writtenObjects) |
| 185 | if newWriteRefId >= MaxInt32 { |
| 186 | return false, fmt.Errorf("too many objects execced %d to serialize", MaxInt32) |
| 187 | } |
| 188 | r.writtenObjects[refKey] = int32(newWriteRefId) |