func isConcrete()

in sdks/go/pkg/beam/core/typex/class.go [97:172]


func isConcrete(t reflect.Type, visited map[uintptr]bool) bool {
	// Check that we haven't hit a recursive loop.
	key := reflect.ValueOf(t).Pointer()
	// If there's an invalid field in a recursive type
	// then the layer above will find it.
	if visited[key] {
		return true
	}
	visited[key] = true

	// Handle special types.
	if t == nil ||
		t == EventTimeType ||
		t.Implements(WindowType) ||
		t == reflectx.Error ||
		t == reflectx.Context ||
		IsUniversal(t) {
		return false
	}

	switch t.Kind() {
	case reflect.Invalid, reflect.UnsafePointer, reflect.Uintptr:
		return false // no unmanageable types

	case reflect.Chan, reflect.Func:
		return false // no unserializable types

	case reflect.Map:
		return isConcrete(t.Elem(), visited) && isConcrete(t.Key(), visited)

	case reflect.Array, reflect.Slice, reflect.Ptr:
		return isConcrete(t.Elem(), visited)

	case reflect.Struct:
		for i := 0; i < t.NumField(); i++ {
			// We ignore private fields under the assumption that they are
			// either not needed or will be coded manually. For combiner
			// accumulators, we need types that need non-trivial coding. Also,
			// Go serialization schemes in general ignore private fields.

			f := t.Field(i)
			if len(f.Name) > 0 {
				r, _ := utf8.DecodeRuneInString(f.Name)
				if unicode.IsUpper(r) && !isConcrete(f.Type, visited) {
					return false
				}
			}
		}
		return true

	case reflect.Interface:
		// Interface types must fail at construction time if no coder is registered for them.
		return true

	case reflect.Bool:
		return true

	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return true

	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return true

	case reflect.Float32, reflect.Float64:
		return true

	case reflect.Complex64, reflect.Complex128:
		return true

	case reflect.String:
		return true

	default:
		panic(fmt.Sprintf("Unexpected type kind: %v", t))
	}
}