mirror of
https://github.com/temporalio/temporal.git
synced 2026-08-30 18:41:49 -07:00
## What changed? - Applied testifylint, staticcheck, and gofix auto-fixes. - Exact commands that were run: ```sh .bin/golangci-lint-v2.9.0 run --allow-parallel-runners --concurrency 4 --fix --enable-only testifylint --build-tags disable_grpc_modules,test_dep --timeout 20m --config=.github/.golangci.yml .bin/golangci-lint-v2.9.0 run --allow-parallel-runners --concurrency 4 --fix --enable-only staticcheck --build-tags disable_grpc_modules,test_dep --timeout 20m --config=.github/.golangci.yml make fmt-gofix make goimports make fmt git diff --check ``` - No manual or AI changes were made; except where commented on. - Some fixes caused lint errors; those were reverted again. - Changes were all reviewed by me.
178 lines
4.4 KiB
Go
178 lines
4.4 KiB
Go
package chasm
|
|
|
|
import (
|
|
"iter"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"go.temporal.io/api/serviceerror"
|
|
)
|
|
|
|
const (
|
|
chasmFieldTypePrefix = "chasm.Field["
|
|
chasmMapTypePrefix = "chasm.Map["
|
|
chasmMSPointerType = "chasm.MSPointer"
|
|
chasmParentPointerTypePrefix = "chasm.ParentPtr["
|
|
|
|
fieldNameTag = "name"
|
|
)
|
|
|
|
type fieldKind uint8
|
|
|
|
const (
|
|
fieldKindUnspecified fieldKind = iota
|
|
fieldKindData
|
|
fieldKindSubField
|
|
fieldKindSubMap
|
|
fieldKindMutableState
|
|
fieldKindParentPtr
|
|
)
|
|
|
|
type fieldInfo struct {
|
|
val reflect.Value
|
|
typ reflect.Type
|
|
name string
|
|
kind fieldKind
|
|
err error
|
|
}
|
|
|
|
// fieldsOf iterates across all CHASM-managed fields of a struct. Other fields
|
|
// are not yielded.
|
|
//
|
|
//nolint:revive // cognitive complexity 26 (> max enabled 25)
|
|
func fieldsOf(valueV reflect.Value) iter.Seq[fieldInfo] {
|
|
valueT := valueV.Type()
|
|
dataFieldName := ""
|
|
return func(yield func(fi fieldInfo) bool) {
|
|
for i := 0; i < valueT.Elem().NumField(); i++ {
|
|
fieldV := valueV.Elem().Field(i)
|
|
fieldT := fieldV.Type()
|
|
if fieldT == UnimplementedComponentT {
|
|
continue
|
|
}
|
|
|
|
fieldN := fieldName(valueT.Elem().Field(i))
|
|
var fieldErr error
|
|
fieldK := fieldKindUnspecified
|
|
if fieldT.AssignableTo(protoMessageT) {
|
|
if dataFieldName != "" {
|
|
fieldErr = serviceerror.NewInternalf("%s.%s: only one data field %s (implements proto.Message) allowed in component", valueT, fieldN, dataFieldName)
|
|
}
|
|
dataFieldName = fieldN
|
|
fieldK = fieldKindData
|
|
} else {
|
|
prefix := genericTypePrefix(fieldT)
|
|
if strings.HasPrefix(prefix, "*") {
|
|
switch prefix[1:] {
|
|
case chasmFieldTypePrefix,
|
|
chasmMapTypePrefix,
|
|
chasmMSPointerType,
|
|
chasmParentPointerTypePrefix:
|
|
fieldErr = serviceerror.NewInternalf("%s.%s: CHASM fields must not be pointers", valueT, fieldN)
|
|
default:
|
|
continue
|
|
}
|
|
} else {
|
|
switch prefix {
|
|
case chasmFieldTypePrefix:
|
|
fieldK = fieldKindSubField
|
|
case chasmMapTypePrefix:
|
|
fieldK = fieldKindSubMap
|
|
case chasmMSPointerType:
|
|
fieldK = fieldKindMutableState
|
|
case chasmParentPointerTypePrefix:
|
|
fieldK = fieldKindParentPtr
|
|
default:
|
|
continue // Skip non-CHASM fields.
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if !yield(fieldInfo{val: fieldV, typ: fieldT, name: fieldN, kind: fieldK, err: fieldErr}) {
|
|
return
|
|
}
|
|
}
|
|
// If the data field is not found, generate one more fake field with only an error set.
|
|
if dataFieldName == "" {
|
|
yield(fieldInfo{err: serviceerror.NewInternalf("%s: no data field (implements proto.Message) found", valueT)})
|
|
}
|
|
}
|
|
}
|
|
|
|
// unmanagedFieldsOf yields all non-CHASM managed fields of a struct.
|
|
func unmanagedFieldsOf(valueT reflect.Type) iter.Seq[fieldInfo] {
|
|
return func(yield func(fi fieldInfo) bool) {
|
|
if valueT.Kind() == reflect.Pointer {
|
|
valueT = valueT.Elem()
|
|
}
|
|
for field := range valueT.Fields() {
|
|
fieldT := field.Type
|
|
if fieldT == UnimplementedComponentT {
|
|
continue
|
|
}
|
|
|
|
// Skip the data field, which is always CHASM-managed.
|
|
if fieldT.AssignableTo(protoMessageT) {
|
|
continue
|
|
}
|
|
|
|
fieldN := fieldName(field)
|
|
prefix := genericTypePrefix(fieldT)
|
|
switch prefix {
|
|
case chasmFieldTypePrefix,
|
|
chasmMapTypePrefix,
|
|
chasmMSPointerType,
|
|
chasmParentPointerTypePrefix:
|
|
continue // Skip CHASM fields.
|
|
default:
|
|
if !yield(fieldInfo{typ: fieldT, name: fieldN}) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func genericTypePrefix(t reflect.Type) string {
|
|
tn := t.String()
|
|
if tn == chasmMSPointerType {
|
|
return chasmMSPointerType
|
|
}
|
|
bracketPos := strings.Index(tn, "[")
|
|
if bracketPos == -1 {
|
|
return ""
|
|
}
|
|
return tn[:bracketPos+1]
|
|
}
|
|
|
|
func fieldName(f reflect.StructField) string {
|
|
if tagName := f.Tag.Get(fieldNameTag); tagName != "" {
|
|
return tagName
|
|
}
|
|
return f.Name
|
|
}
|
|
|
|
// visibilityFieldT is the reflect.Type for Field[*Visibility], used to detect
|
|
// components that use Visibility at registration time.
|
|
var visibilityFieldT = reflect.TypeFor[Field[*Visibility]]()
|
|
|
|
// hasVisibilityField returns true if the given component type has a Field[*Visibility].
|
|
// This is used at registration time to validate that archetypes using Visibility
|
|
// have configured a businessID alias.
|
|
func hasVisibilityField(componentT reflect.Type) bool {
|
|
if componentT.Kind() == reflect.Pointer {
|
|
componentT = componentT.Elem()
|
|
}
|
|
if componentT.Kind() != reflect.Struct {
|
|
return false
|
|
}
|
|
for field := range componentT.Fields() {
|
|
fieldT := field.Type
|
|
if fieldT == visibilityFieldT {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|