Пример #1
0
func initializeSliceToGet(object *object, value reflect.Value) error {
	typo := value.Type()

	bid, ok := kindTypeMapping[typo.Elem().Kind()]
	if !ok {
		return errors.New("encountered an unsupported datatype")
	}

	if err := checkArrayType(object.tid, bid); err != nil {
		return err
	}

	length, err := computeArrayLength(object.tid)
	if err != nil {
		return err
	}

	buffer := reflect.MakeSlice(typo, int(length), int(length))
	shadow := reflect.Indirect(reflect.New(typo))
	shadow.Set(buffer)

	src := (*reflect.SliceHeader)(unsafe.Pointer(shadow.UnsafeAddr()))
	dst := (*reflect.SliceHeader)(unsafe.Pointer(value.UnsafeAddr()))

	dst.Data, src.Data = src.Data, dst.Data
	dst.Cap, src.Cap = src.Cap, dst.Cap
	dst.Len, src.Len = src.Len, dst.Len

	object.data = unsafe.Pointer(dst.Data)
	object.flag |= flagVariableLength

	return nil
}
Пример #2
0
func valueHeader(v reflect.Value) (h *reflect.SliceHeader) {
	if v.IsValid() {
		size := int(v.Type().Size())
		h = &reflect.SliceHeader{v.UnsafeAddr(), size, size}
	}
	return
}
Пример #3
0
func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
	mtag := newMultiTag(string(sfield.Tag))

	if err := mtag.Parse(); err != nil {
		return true, err
	}

	subgroup := mtag.Get("group")

	if len(subgroup) != 0 {
		ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr()))
		description := mtag.Get("description")

		group, err := g.AddGroup(subgroup, description, ptrval.Interface())
		if err != nil {
			return true, err
		}

		group.Namespace = mtag.Get("namespace")
		group.Hidden = mtag.Get("hidden") != ""

		return true, nil
	}

	return false, nil
}
Пример #4
0
//Ptr is simply a copy of the go-gl Ptr function, it takes in argument a slice, uintptr or pointer and makes an unsafe.Pointer with it.
func Ptr(v interface{}) unsafe.Pointer {

	if v == nil {
		return unsafe.Pointer(nil)
	}

	rv := reflect.ValueOf(v)
	var et reflect.Value
	switch rv.Type().Kind() {
	case reflect.Uintptr:
		offset, _ := v.(uintptr)
		return unsafe.Pointer(offset)
	case reflect.Ptr:
		if rv.IsNil() {
			return unsafe.Pointer(nil)
		}
		et = rv.Elem()
	case reflect.Slice:
		if rv.IsNil() || rv.Len() == 0 {
			return unsafe.Pointer(nil)
		}
		et = rv.Index(0)
	default:
		panic("type must be a pointer, a slice, uintptr or nil")
	}

	return unsafe.Pointer(et.UnsafeAddr())
}
Пример #5
0
// Gob assumes it can call UnsafeAddr on any Value
// in order to get a pointer it can copy data from.
// Values that have just been created and do not point
// into existing structs or slices cannot be addressed,
// so simulate it by returning a pointer to a copy.
// Each call allocates once.
func unsafeAddr(v reflect.Value) uintptr {
	if v.CanAddr() {
		return v.UnsafeAddr()
	}
	x := reflect.New(v.Type()).Elem()
	x.Set(v)
	return x.UnsafeAddr()
}
Пример #6
0
// Gob assumes it can call UnsafeAddr on any Value
// in order to get a pointer it can copy data from.
// Values that have just been created and do not point
// into existing structs or slices cannot be addressed,
// so simulate it by returning a pointer to a copy.
// Each call allocates once.
func unsafeAddr(v reflect.Value) unsafe.Pointer {
	if v.CanAddr() {
		return unsafe.Pointer(v.UnsafeAddr())
	}
	x := reflect.New(v.Type()).Elem()
	x.Set(v)
	return unsafe.Pointer(x.UnsafeAddr())
}
Пример #7
0
// encodeReflectValue is a helper for maps. It encodes the value v.
func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir int) {
	for i := 0; i < indir && v != nil; i++ {
		v = reflect.Indirect(v)
	}
	if v == nil {
		errorf("gob: encodeReflectValue: nil element")
	}
	op(nil, state, unsafe.Pointer(v.UnsafeAddr()))
}
Пример #8
0
// Obtain a copy of a private byte slice.
func copyPrivateByteSlice(value reflect.Value) []byte {
	newSlice := []byte{}
	_newSlice := (*reflect.SliceHeader)(unsafe.Pointer(&newSlice))
	_origSlice := (*reflect.SliceHeader)(unsafe.Pointer(value.UnsafeAddr()))
	_newSlice.Data = _origSlice.Data
	_newSlice.Len = _origSlice.Len
	_newSlice.Cap = _origSlice.Cap
	return newSlice
}
Пример #9
0
// Traverses recursively both values, assigning src's fields values to dst.
// The map argument tracks comparisons that have already been seen, which allows
// short circuiting on recursive types.
func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int) error {
	if !src.IsValid() {
		return nil
	}
	if dst.CanAddr() {
		addr := dst.UnsafeAddr()
		h := 17 * addr
		seen := visited[h]
		typ := dst.Type()
		for p := seen; p != nil; p = p.next {
			if p.ptr == addr && p.typ == typ {
				return nil
			}
		}
		// Remember, remember...
		visited[h] = &visit{addr, typ, seen}
	}
	switch dst.Kind() {
	case reflect.Struct:
		for i, n := 0, dst.NumField(); i < n; i++ {
			if err := deepMerge(dst.Field(i), src.Field(i), visited, depth+1); err != nil {
				return err
			}
		}
	case reflect.Map:
		for _, key := range src.MapKeys() {
			srcElement := src.MapIndex(key)
			if !srcElement.IsValid() {
				continue
			}
			dstElement := dst.MapIndex(key)
			switch reflect.TypeOf(srcElement.Interface()).Kind() {
			case reflect.Struct:
				fallthrough
			case reflect.Map:
				if err := deepMerge(dstElement, srcElement, visited, depth+1); err != nil {
					return err
				}
			default:
				dst.SetMapIndex(key, srcElement)
			}
			if !dstElement.IsValid() {
				dst.SetMapIndex(key, srcElement)
			}
		}
	case reflect.Interface:
		if err := deepMerge(dst.Elem(), src.Elem(), visited, depth+1); err != nil {
			return err
		}
	default:
		if dst.CanSet() && isEmptyValue(dst) {
			dst.Set(src)
		}
	}
	return nil
}
Пример #10
0
func injectIoc(target reflect.Value, basic *Basic) {
	for target.Kind() == reflect.Ptr {
		target = target.Elem()
	}
	typeIndex := getIocTypeIndex(target.Type())
	targetAddr := target.UnsafeAddr()
	for _, singleIndex := range typeIndex {
		var pointer **Basic = (**Basic)(unsafe.Pointer(targetAddr + singleIndex))
		*pointer = basic
	}
}
Пример #11
0
//Encodes the value into to the writer in the msgpack format
func (enc *Encoder) EncodeValue(value reflect.Value) error {
	if value.Kind() != reflect.Ptr {
		panic("Encode requires a pointer type")
	}
	value = value.Elem()
	eng := getEngine(value.Type())

	if encode, ok := eng.encode.(encodeFunc); ok {
		return encode(enc, unsafe.Pointer(value.UnsafeAddr()))
	} else {
		encode := eng.encode.(encodeReflectFunc)
		return encode(enc, value)
	}
}
Пример #12
0
//Decodes the value from the reader in the msgpack format
func (dec *Decoder) DecodeValue(value reflect.Value) error {
	if value.Kind() != reflect.Ptr {
		panic("Decode requires a pointer type")
	}
	value = value.Elem()
	eng := getEngine(value.Type())

	if decode, ok := eng.decode.(decodeFunc); ok {
		return decode(dec, unsafe.Pointer(value.UnsafeAddr()))
	} else {
		decode := eng.decode.(decodeReflectFunc)
		return decode(dec, value)
	}
}
Пример #13
0
func sliceHeaderFromValue(v reflect.Value) (s *reflect.SliceHeader) {
	switch v.Kind() {
	case reflect.Slice:
		if !v.CanAddr() {
			x := reflect.New(v.Type()).Elem()
			x.Set(v)
			v = x
		}
		s = (*reflect.SliceHeader)(unsafe.Pointer(v.UnsafeAddr()))
	case reflect.Ptr, reflect.Interface:
		s = sliceHeaderFromValue(v.Elem())
	}
	return
}
Пример #14
0
func decode_value(cv *Value, rv reflect.Value) {
	//fmt.Printf("rv: %v\n",rv.Type())
	kind := rv.Type().Kind()
	op := dec_op_table[kind]
	switch kind {
	default:
		//println("-->",kind.String())
		op(cv, unsafe.Pointer(rv.UnsafeAddr()))
		//println("<--",kind.String())
	case reflect.Array:
		op(cv, unsafe.Pointer(&rv))
	case reflect.Ptr:
		//fmt.Printf("--> ptr\n")
		op(cv, unsafe.Pointer(rv.UnsafeAddr()))
		//fmt.Printf("<-- ptr\n")
	case reflect.Slice:
		op(cv, unsafe.Pointer(rv.UnsafeAddr()))
	case reflect.Struct:
		op(cv, unsafe.Pointer(&rv))
	case reflect.String:
		//println("==>",kind.String())
		op(cv, unsafe.Pointer(rv.UnsafeAddr()))
		//println("<==",kind.String())
	}
	//fmt.Printf("rv: %v [done]\n", rv.Type())
}
Пример #15
0
func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) {
	defer catchError(&enc.err)
	engine := enc.lockAndGetEncEngine(ut)
	indir := ut.indir
	if ut.isGobEncoder {
		indir = int(ut.encIndir)
	}
	for i := 0; i < indir; i++ {
		value = reflect.Indirect(value)
	}
	if !ut.isGobEncoder && value.Type().Kind() == reflect.Struct {
		enc.encodeStruct(b, engine, value.UnsafeAddr())
	} else {
		enc.encodeSingle(b, engine, value.UnsafeAddr())
	}
}
Пример #16
0
// Traverses recursively both values, assigning src's fields values to dst.
// The map argument tracks comparisons that have already been seen, which allows
// short circuiting on recursive types.
func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) {
	if dst.CanAddr() {
		addr := dst.UnsafeAddr()
		h := 17 * addr
		seen := visited[h]
		typ := dst.Type()
		for p := seen; p != nil; p = p.next {
			if p.ptr == addr && p.typ == typ {
				return nil
			}
		}
		// Remember, remember...
		visited[h] = &visit{addr, typ, seen}
	}
	return // TODO refactor
}
Пример #17
0
func readSlice(iv reflect.Value, p unsafe.Pointer, c C.size_t, s C.size_t) error {
	w := reflect.MakeSlice(iv.Type(), int(c), int(c))
	C.memcpy(unsafe.Pointer(w.Pointer()), p, c*s)

	iw := reflect.Indirect(reflect.New(iv.Type()))
	iw.Set(w)

	// FIXME: Bad, bad, bad! But how else to fill in unexported fields?
	src := (*reflect.SliceHeader)(unsafe.Pointer(iw.UnsafeAddr()))
	dst := (*reflect.SliceHeader)(unsafe.Pointer(iv.UnsafeAddr()))

	dst.Data, src.Data = src.Data, dst.Data
	dst.Len, src.Len = src.Len, dst.Len
	dst.Cap, src.Cap = src.Cap, dst.Cap

	return nil
}
Пример #18
0
func isCycle(x reflect.Value, seen map[comparison]bool) bool {
	if !x.IsValid() {
		return false
	}

	// cycle check
	if x.CanAddr() {
		xptr := unsafe.Pointer(x.UnsafeAddr())
		c := comparison{xptr, x.Type()}
		if seen[c] {
			return true // already seen
		}
		seen[c] = true
	}

	switch x.Kind() {
	case reflect.Ptr, reflect.Interface:
		return isCycle(x.Elem(), seen)

	case reflect.Array, reflect.Slice:
		for i := 0; i < x.Len(); i++ {
			if isCycle(x.Index(i), seen) {
				return true
			}
		}
		return false

	case reflect.Struct:
		for i, n := 0, x.NumField(); i < n; i++ {
			if isCycle(x.Field(i), seen) {
				return true
			}
		}
		return false

	case reflect.Map:
		for _, k := range x.MapKeys() {
			if isCycle(x.MapIndex(k), seen) {
				return true
			}
		}
		return false
	}
	return false
}
Пример #19
0
func getPointer(rv reflect.Value) uintptr {
	var rvptr uintptr

	switch rv.Kind() {
	case reflect.Map, reflect.Slice:
		rvptr = rv.Pointer()
	case reflect.Interface:
		// FIXME: still needed?
		return getPointer(rv.Elem())
	case reflect.Ptr:
		rvptr = rv.Pointer()
	case reflect.String:
		ps := (*reflect.StringHeader)(unsafe.Pointer(rv.UnsafeAddr()))
		rvptr = ps.Data
	}

	return rvptr
}
Пример #20
0
func valueDecoder(data interface{}) (unsafe.Pointer, typeDecoder, error) {
	var v reflect.Value
	switch d := reflect.ValueOf(data); d.Kind() {
	case reflect.Ptr:
		v = d.Elem()
	case reflect.Slice:
		v = d
	case reflect.Invalid:
		return nil, nil, errors.New("can't decode into nil")
	default:
		return nil, nil, errors.New("invalid type " + d.Type().String())
	}
	dec, err := makeDecoder(v.Type())
	if err != nil {
		return nil, nil, err
	}
	return unsafe.Pointer(v.UnsafeAddr()), dec, err
}
Пример #21
0
func checkCircle(x reflect.Value, seen objInfoSet) bool {
	if !x.IsValid() {
		return false
	}
	if x.CanAddr() {
		objinfo := objInfo{unsafe.Pointer(x.UnsafeAddr()), x.Type()}
		if _, ok := seen[objinfo]; ok {
			return true
		}
		seen[objinfo] = true
	}
	switch x.Kind() {
	case reflect.Ptr, reflect.Interface:
		return checkCircle(x.Elem(), copyObjInfoSet(seen))

	case reflect.Array, reflect.Slice:
		for i := 0; i < x.Len(); i++ {
			if checkCircle(x.Index(i), copyObjInfoSet(seen)) {
				return true
			}
		}
		return false

	case reflect.Struct:
		for i, n := 0, x.NumField(); i < n; i++ {
			if checkCircle(x.Field(i), copyObjInfoSet(seen)) {
				return true
			}
		}
		return false

	case reflect.Map:
		for _, k := range x.MapKeys() {
			if checkCircle(x.MapIndex(k), copyObjInfoSet(seen)) {
				return true
			}
		}
		return false
	}
	return false
}
Пример #22
0
Файл: config.go Проект: kho/easy
func setValue(value reflect.Value, s string) error {
	ptr := unsafe.Pointer(value.UnsafeAddr())
	switch value.Type().Kind() {
	case reflect.Bool:
		return setBool(ptr, s)
	case reflect.Float64:
		return setFloat64(ptr, s)
	case reflect.Int64:
		return setInt64(ptr, s)
	case reflect.Int:
		return setInt(ptr, s)
	case reflect.String:
		return setString(ptr, s)
	case reflect.Uint64:
		return setUint64(ptr, s)
	case reflect.Uint:
		return setUint(ptr, s)
	default:
		panic(fmt.Sprintf("unsupported type: %v", value.Type()))
	}
}
Пример #23
0
// Gets a node from value `src` and using `r` to search for previously visited
// nodes. Returns true as a second parameter if node has already been graphed;
// false if it still needs to.
func getNode(src reflect.Value, r *resolver) (*node, bool) {
	n, ok := (*node)(nil), false

	if src.CanAddr() {
		// if we are addressable then make sure we get the node from
		// the resolver
		n, ok = r.resolveAddr(src.UnsafeAddr())
	} else {
		// we aren't and have to recreate a fresh node
		n = newNode()
	}

	if !ok {
		// we are either a completely new node and we need to set our
		// value
		n.val = getVal(src)
	}

	// return the node
	return n, ok
}
Пример #24
0
func cyclic(x reflect.Value, seen map[ptr]bool) bool {
	if x.CanAddr() {
		p := ptr{unsafe.Pointer(x.UnsafeAddr()), x.Type()}
		if seen[p] {
			return true
		}
		seen[p] = true
	}
	switch x.Kind() {
	case reflect.Ptr, reflect.Interface:
		return cyclic(x.Elem(), seen)

	case reflect.Array, reflect.Slice:
		for i := 0; i < x.Len(); i++ {
			if cyclic(x.Index(i), seen) {
				return true
			}
		}
		return false

	case reflect.Struct:
		for i, n := 0, x.NumField(); i < n; i++ {
			if cyclic(x.Field(i), seen) {
				return true
			}
		}
		return false

	case reflect.Map:
		for _, k := range x.MapKeys() {
			if cyclic(x.MapIndex(k), seen) || cyclic(k, seen) {
				return true
			}
		}
		return false
	default:
		return false
	}
	panic("unreachable")
}
Пример #25
0
Файл: config.go Проект: kho/easy
func addFieldFlag(field reflect.StructField, value reflect.Value, fs *flag.FlagSet) {
	name, usage := getFieldNameUsage(field)
	ptr := unsafe.Pointer(value.UnsafeAddr())
	switch field.Type.Kind() {
	case reflect.Bool:
		fs.BoolVar((*bool)(ptr), name, *(*bool)(ptr), usage)
	case reflect.Float64:
		fs.Float64Var((*float64)(ptr), name, *(*float64)(ptr), usage)
	case reflect.Int64:
		fs.Int64Var((*int64)(ptr), name, *(*int64)(ptr), usage)
	case reflect.Int:
		fs.IntVar((*int)(ptr), name, *(*int)(ptr), usage)
	case reflect.String:
		fs.StringVar((*string)(ptr), name, *(*string)(ptr), usage)
	case reflect.Uint64:
		fs.Uint64Var((*uint64)(ptr), name, *(*uint64)(ptr), usage)
	case reflect.Uint:
		fs.UintVar((*uint)(ptr), name, *(*uint)(ptr), usage)
	default:
		panic(fmt.Sprintf("unsupported type: %v", field.Type))
	}
}
Пример #26
0
func f() {
	var x unsafe.Pointer
	var y uintptr
	x = unsafe.Pointer(y) // ERROR "possible misuse of unsafe.Pointer"
	y = uintptr(x)

	// only allowed pointer arithmetic is ptr +/-/&^ num.
	// num+ptr is technically okay but still flagged: write ptr+num instead.
	x = unsafe.Pointer(uintptr(x) + 1)
	x = unsafe.Pointer(1 + uintptr(x))          // ERROR "possible misuse of unsafe.Pointer"
	x = unsafe.Pointer(uintptr(x) + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
	x = unsafe.Pointer(uintptr(x) - 1)
	x = unsafe.Pointer(1 - uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
	x = unsafe.Pointer(uintptr(x) &^ 3)
	x = unsafe.Pointer(1 &^ uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"

	// certain uses of reflect are okay
	var v reflect.Value
	x = unsafe.Pointer(v.Pointer())
	x = unsafe.Pointer(v.UnsafeAddr())
	var s1 *reflect.StringHeader
	x = unsafe.Pointer(s1.Data)
	var s2 *reflect.SliceHeader
	x = unsafe.Pointer(s2.Data)
	var s3 reflect.StringHeader
	x = unsafe.Pointer(s3.Data) // ERROR "possible misuse of unsafe.Pointer"
	var s4 reflect.SliceHeader
	x = unsafe.Pointer(s4.Data) // ERROR "possible misuse of unsafe.Pointer"

	// but only in reflect
	var vv V
	x = unsafe.Pointer(vv.Pointer())    // ERROR "possible misuse of unsafe.Pointer"
	x = unsafe.Pointer(vv.UnsafeAddr()) // ERROR "possible misuse of unsafe.Pointer"
	var ss1 *StringHeader
	x = unsafe.Pointer(ss1.Data) // ERROR "possible misuse of unsafe.Pointer"
	var ss2 *SliceHeader
	x = unsafe.Pointer(ss2.Data) // ERROR "possible misuse of unsafe.Pointer"

}
Пример #27
0
Файл: gl.go Проект: Nvveen/gl
func ptr(v interface{}) unsafe.Pointer {

	if v == nil {
		return unsafe.Pointer(nil)
	}

	rv := reflect.ValueOf(v)
	var et reflect.Value
	switch rv.Type().Kind() {
	case reflect.Uintptr:
		offset, _ := v.(uintptr)
		return unsafe.Pointer(offset)
	case reflect.Ptr:
		et = rv.Elem()
	case reflect.Slice:
		et = rv.Index(0)
	default:
		panic(ErrorPointerType)
	}

	return unsafe.Pointer(et.UnsafeAddr())
}
Пример #28
0
func (e *Encoder) preEncodeValue(rv reflect.Value) (rv2 reflect.Value, sptr uintptr, proceed bool) {
	// use a goto statement instead of a recursive function for ptr/interface.
TOP:
	switch rv.Kind() {
	case reflect.Ptr:
		if rv.IsNil() {
			e.e.EncodeNil()
			return
		}
		rv = rv.Elem()
		if e.h.CheckCircularRef && rv.Kind() == reflect.Struct {
			// TODO: Movable pointers will be an issue here. Future problem.
			sptr = rv.UnsafeAddr()
			break TOP
		}
		goto TOP
	case reflect.Interface:
		if rv.IsNil() {
			e.e.EncodeNil()
			return
		}
		rv = rv.Elem()
		goto TOP
	case reflect.Slice, reflect.Map:
		if rv.IsNil() {
			e.e.EncodeNil()
			return
		}
	case reflect.Invalid, reflect.Func:
		e.e.EncodeNil()
		return
	}

	proceed = true
	rv2 = rv
	return
}
Пример #29
0
func encode_value(cv *Value, rv reflect.Value) {

	kind := rv.Type().Kind()
	op := enc_op_table[kind]
	switch kind {
	default:
		op(cv, unsafe.Pointer(rv.UnsafeAddr()))
	case reflect.Array:
		op(cv, unsafe.Pointer(&rv))
	case reflect.Ptr:
		op(cv, unsafe.Pointer(rv.Pointer()))
	case reflect.Slice:
		op(cv, unsafe.Pointer(rv.UnsafeAddr()))
	case reflect.Struct:
		op(cv, unsafe.Pointer(&rv))
	case reflect.String:
		op(cv, unsafe.Pointer(rv.UnsafeAddr()))
	}
}
Пример #30
0
func (p *printer) printValue(v reflect.Value, showType, quote bool) {
	if p.depth > 10 {
		io.WriteString(p, "!%v(DEPTH EXCEEDED)")
		return
	}

	switch v.Kind() {
	case reflect.Bool:
		p.printInline(v, v.Bool(), showType)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		p.printInline(v, v.Int(), showType)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		p.printInline(v, v.Uint(), showType)
	case reflect.Float32, reflect.Float64:
		p.printInline(v, v.Float(), showType)
	case reflect.Complex64, reflect.Complex128:
		fmt.Fprintf(p, "%#v", v.Complex())
	case reflect.String:
		p.fmtString(v.String(), quote)
	case reflect.Map:
		t := v.Type()
		if showType {
			io.WriteString(p, t.String())
		}
		writeByte(p, '{')
		if nonzero(v) {
			expand := !canInline(v.Type())
			pp := p
			if expand {
				writeByte(p, '\n')
				pp = p.indent()
			}
			keys := v.MapKeys()
			for i := 0; i < v.Len(); i++ {
				showTypeInStruct := true
				k := keys[i]
				mv := v.MapIndex(k)
				pp.printValue(k, false, true)
				writeByte(pp, ':')
				if expand {
					writeByte(pp, '\t')
				}
				showTypeInStruct = t.Elem().Kind() == reflect.Interface
				pp.printValue(mv, showTypeInStruct, true)
				if expand {
					io.WriteString(pp, ",\n")
				} else if i < v.Len()-1 {
					io.WriteString(pp, ", ")
				}
			}
			if expand {
				pp.tw.Flush()
			}
		}
		writeByte(p, '}')
	case reflect.Struct:
		t := v.Type()
		if v.CanAddr() {
			addr := v.UnsafeAddr()
			vis := visit{addr, t}
			if vd, ok := p.visited[vis]; ok && vd < p.depth {
				p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false)
				break // don't print v again
			}
			p.visited[vis] = p.depth
		}

		if showType {
			io.WriteString(p, t.String())
		}
		writeByte(p, '{')
		if nonzero(v) {
			expand := !canInline(v.Type())
			pp := p
			if expand {
				writeByte(p, '\n')
				pp = p.indent()
			}
			for i := 0; i < v.NumField(); i++ {
				showTypeInStruct := true
				if f := t.Field(i); f.Name != "" {
					io.WriteString(pp, f.Name)
					writeByte(pp, ':')
					if expand {
						writeByte(pp, '\t')
					}
					showTypeInStruct = labelType(f.Type)
				}
				pp.printValue(getField(v, i), showTypeInStruct, true)
				if expand {
					io.WriteString(pp, ",\n")
				} else if i < v.NumField()-1 {
					io.WriteString(pp, ", ")
				}
			}
			if expand {
				pp.tw.Flush()
			}
		}
		writeByte(p, '}')
	case reflect.Interface:
		switch e := v.Elem(); {
		case e.Kind() == reflect.Invalid:
			io.WriteString(p, "nil")
		case e.IsValid():
			pp := *p
			pp.depth++
			pp.printValue(e, showType, true)
		default:
			io.WriteString(p, v.Type().String())
			io.WriteString(p, "(nil)")
		}
	case reflect.Array, reflect.Slice:
		t := v.Type()
		if showType {
			io.WriteString(p, t.String())
		}
		if v.Kind() == reflect.Slice && v.IsNil() && showType {
			io.WriteString(p, "(nil)")
			break
		}
		if v.Kind() == reflect.Slice && v.IsNil() {
			io.WriteString(p, "nil")
			break
		}
		writeByte(p, '{')
		expand := !canInline(v.Type())
		pp := p
		if expand {
			writeByte(p, '\n')
			pp = p.indent()
		}
		for i := 0; i < v.Len(); i++ {
			showTypeInSlice := t.Elem().Kind() == reflect.Interface
			pp.printValue(v.Index(i), showTypeInSlice, true)
			if expand {
				io.WriteString(pp, ",\n")
			} else if i < v.Len()-1 {
				io.WriteString(pp, ", ")
			}
		}
		if expand {
			pp.tw.Flush()
		}
		writeByte(p, '}')
	case reflect.Ptr:
		e := v.Elem()
		if !e.IsValid() {
			writeByte(p, '(')
			io.WriteString(p, v.Type().String())
			io.WriteString(p, ")(nil)")
		} else {
			pp := *p
			pp.depth++
			writeByte(pp, '&')
			pp.printValue(e, true, true)
		}
	case reflect.Chan:
		x := v.Pointer()
		if showType {
			writeByte(p, '(')
			io.WriteString(p, v.Type().String())
			fmt.Fprintf(p, ")(%#v)", x)
		} else {
			fmt.Fprintf(p, "%#v", x)
		}
	case reflect.Func:
		io.WriteString(p, v.Type().String())
		io.WriteString(p, " {...}")
	case reflect.UnsafePointer:
		p.printInline(v, v.Pointer(), showType)
	case reflect.Invalid:
		io.WriteString(p, "nil")
	}
}