Files
tasks/chasm/parent_pointer.go
zeekay 5a601d081b rebrand: go.temporal.io/server -> github.com/hanzoai/tasks
Full module path rebrand from Temporal to Hanzo Tasks:
- go.mod module: github.com/hanzoai/tasks
- All internal Go imports updated (1906 files)
- cmd/server renamed to cmd/tasksd
- Binary name: tasksd (was temporal-server)
- Docker images: hanzoai/tasks (was temporalio/server)
- README rewritten with Hanzo Tasks branding
- LLM.md created with integration notes
- Makefile, goreleaser, CI workflows updated
- go.temporal.io/sdk and go.temporal.io/api imports preserved (separate repos)

Fork of Temporal.io (MIT license).
2026-03-19 10:36:40 -07:00

103 lines
3.1 KiB
Go

package chasm
import (
"fmt"
"reflect"
"go.temporal.io/api/serviceerror"
"github.com/hanzoai/tasks/common/softassert"
)
const (
parentPtrInternalFieldName = "Internal"
)
// ParentPtr is a in-memory pointer to the parent component of a CHASM component.
//
// CHASM map is not a component, so if a component is inside a map, its ParentPtr
// will point to the nearest ancestor component that is not a map.
//
// ParentPtr is only initialized and available for use **after** the transition that
// creates the component using ParentPtr is completed.
type ParentPtr[T any] struct {
// Exporting this field as this generic struct needs to be created via reflection,
// and reflection can't set private fields.
Internal parentPtrInternal
}
type parentPtrInternal struct {
// Storing currentNode instead of parent component Node here so that
// we can differentiate between root node and non-initialized ParentPtr.
currentNode *Node
}
// Get returns the parent component, deserializing it if necessary.
// Panics rather than returning an error, as errors are supposed to be handled by the framework as opposed to the
// application.
func (p ParentPtr[T]) Get(chasmContext Context) T {
vT, ok := p.TryGet(chasmContext)
if !ok {
// nolint:forbidigo // Panic is intended here for framework error handling.
panic(serviceerror.NewInternal("expect parent component value but got nil"))
}
return vT
}
// TryGet returns the parent component and a boolean indicating if the value was found,
// deserializing if necessary.
// Panics rather than returning an error, as errors are supposed to be handled by the framework as opposed to the
// application.
func (p ParentPtr[T]) TryGet(chasmContext Context) (T, bool) {
var nilT T
if p.Internal.currentNode == nil {
// ParentPtr not initialized
return nilT, false
}
parent := p.Internal.currentNode.parent
if parent == nil {
return nilT, false
}
for parent.isMap() {
parent = parent.parent
if parent == nil {
encodedPath, _ := p.Internal.currentNode.getEncodedPath()
// nolint:forbidigo // Panic is intended here for framework error handling.
panic(softassert.UnexpectedInternalErr(
p.Internal.currentNode.logger,
"unable to find parent component for CHASM component inside a map",
fmt.Errorf("child node name: %s", encodedPath),
))
}
}
if !parent.isComponent() {
// nolint:forbidigo // Panic is intended here for framework error handling.
panic(softassert.UnexpectedInternalErr(
parent.logger,
"unexpected CHASM node that has a child component",
fmt.Errorf("node %s, node metadata: %s",
parent.nodeName,
parent.serializedNode.GetMetadata().String(),
),
))
}
if err := parent.prepareComponentValue(chasmContext); err != nil {
// nolint:forbidigo // Panic is intended here for framework error handling.
panic(err)
}
if parent.value == nil {
return nilT, false
}
vT, isT := parent.value.(T)
if !isT {
// nolint:forbidigo // Panic is intended here for framework error handling.
panic(serviceerror.NewInternalf("parent component value doesn't implement %s", reflect.TypeFor[T]().Name()))
}
return vT, true
}