// ChildAt returns the nth field or slice element. If that value is
// a pointer or an interface, it is dereferenced before returning.
// Nil pointers, interfaces, and empty slices will return nil here.
ChildAt returns the nth field or slice element. If that value is
a pointer or an interface, it is dereferenced before returning.
Nil pointers, interfaces, and empty slices will return nil here.
// ChildAt returns the nth field or slice element . If that value is // a pointer or an interface it is dereferenced before returning . // Nil pointers interfaces and empty slices will return nil here .
func (a *Abstract) ChildAt(index int) *Abstract {
	var chaseType *TypeData
	var chaseValue Ptr
	switch a.typeData.Kind {
	case KindStruct:
		f := a.typeData.Fields[index]
		chaseType = f.targetData
		chaseValue = Ptr(uintptr(a.value) + f.Offset)
	case KindSlice:
		header := (*reflect.SliceHeader)(a.value)
		if index < 0 || index >= header.Len {
			panic(fmt.Errorf("index out of range: %d", index))
		}
		chaseType = a.typeData.elemData
		chaseValue = Ptr(header.Data + uintptr(index)*chaseType.SizeOf)
	default:
		panic(fmt.Errorf("unimplemented: %d", a.typeData.Kind))
	}
	for {
		if chaseValue == nil {
			return nil
		}
		switch chaseType.Kind {
		case KindSlice:
			header := (*reflect.SliceHeader)(chaseValue)
			if header.Len == 0 {
				return nil
			}
			fallthrough
		case KindStruct:
			return &Abstract{
				engine:   a.engine,
				typeData: chaseType,
				value:    chaseValue,
			}
		case KindPointer:
			chaseValue = *(*Ptr)(chaseValue)
			chaseType = chaseType.elemData
		case KindInterface:
			elemType := chaseType.IntfType(chaseValue)
			if elemType == 0 {
				return nil
			}
			chaseType = a.engine.typeData(elemType)
			chaseValue = ((*[2]Ptr)(chaseValue))[1]
		default:
			panic(fmt.Errorf("unimplemented: %d", chaseType.Kind))
		}
	}
}
func ( a * Abstract ) ChildAt ( index int ) * Abstract { var chaseType * TypeData var chaseValue Ptr switch a . typeData . Kind { case KindStruct : f := a . typeData . Fields [ index ] chaseType = f . targetData chaseValue = Ptr ( uintptr ( a . value ) + f . Offset ) case KindSlice : header := ( * reflect . SliceHeader ) ( a . value ) if index < 0 || index >= header . Len { panic ( fmt . Errorf ( " " , index ) ) } chaseType = a . typeData . elemData chaseValue = Ptr ( header . Data + uintptr ( index ) * chaseType . SizeOf ) default : panic ( fmt . Errorf ( " " , a . typeData . Kind ) ) } for { if chaseValue == nil { return nil } switch chaseType . Kind { case KindSlice : header := ( * reflect . SliceHeader ) ( chaseValue ) if header . Len == 0 { return nil } fallthrough case KindStruct : return & Abstract { engine : a . engine , typeData : chaseType , value : chaseValue , } case KindPointer : chaseValue = * ( * Ptr ) ( chaseValue ) chaseType = chaseType . elemData case KindInterface : elemType := chaseType . IntfType ( chaseValue ) if elemType == 0 { return nil } chaseType = a . engine . typeData ( elemType ) chaseValue = ( ( * [ 2 ] Ptr ) ( chaseValue ) ) [ 1 ] default : panic ( fmt . Errorf ( " " , chaseType . Kind ) ) } } }
ChildAt returns the nth field or slice element.
ChildAt returns the nth field or slice element .
// First, we select the child value. // We should never have returned an Abstract wrapping anything other // than a struct or a slice. Getting here indicates a problem // with code-generation. // Now, we traverse pointers and interfaces until we arrive at // a struct or a slice. // Special-case: If the slice is empty, return nil // We wrap structs and slices in a new Abstract. // We try to dereference pointers and loop around. // Interfaces return a more specialized type.