in ref.go [105:157]
func (e *Encoder) checkRefMap(v reflect.Value) (int, bool) {
var (
kind reflect.Kind
tp reflect.Type
addr unsafe.Pointer
)
if v.Kind() == reflect.Ptr {
for v.Elem().Kind() == reflect.Ptr {
v = v.Elem()
}
kind = v.Elem().Kind()
if kind != reflect.Invalid {
tp = v.Elem().Type()
}
if kind == reflect.Slice || kind == reflect.Map {
addr = unsafe.Pointer(v.Elem().Pointer())
} else {
addr = unsafe.Pointer(v.Pointer())
}
} else {
kind = v.Kind()
tp = v.Type()
switch kind {
case reflect.Slice, reflect.Map:
addr = unsafe.Pointer(v.Pointer())
default:
addr = unsafe.Pointer(PackPtr(v).Pointer())
}
}
if addr == _emptySliceAddr || addr == _nilMapAddr {
return 0, false
}
if elem, ok := e.refMap[addr]; ok {
if elem.kind == kind {
// If kind is not struct, just return the index. Otherwise,
// check whether the types are same, because the different
// empty struct may share the same address and kind.
if elem.kind != reflect.Struct {
return elem.index, ok
} else if elem.tp == tp {
return elem.index, ok
}
}
return 0, false
}
n := len(e.refMap)
e.refMap[addr] = _refElem{kind, tp, n}
return 0, false
}