mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-25 01:00:16 -05:00
In "package tofu" today we try to do everything using a generic acyclic graph model and generic graph walk, which _works_ but tends to make every other part of the problem very hard to follow because we rely a lot on sidecar shared mutable data structures to propagate results between the isolated operations. This is the beginning of an experimental new way to do it where the "graph" is implied by a model that more closely represents how the language itself works, with explicit modelling of the relationships between different types of objects and letting results flow directly from one object to another without any big shared mutable state. There's still a lot to do before this is actually complete enough to evaluate whether it's a viable new design, but I'm considering this a good starting checkpoint since there's enough here to run a simple test of propagating data all the way from input variables to output values via intermediate local values. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
73 lines
2.7 KiB
Go
73 lines
2.7 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package grapheval
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/apparentlymart/go-workgraph/workgraph"
|
|
)
|
|
|
|
// ContextWithWorker returns a child of the given context that is associated
|
|
// with the given [workgraph.Worker].
|
|
//
|
|
// This is a very low-level API for use by code that is interacting directly
|
|
// with the [workgraph] package API. Callers should prefer to use the
|
|
// higher-level wrappers in this package whenever possible, because they
|
|
// manage context-based worker tracking automatically on the caller's behalf.
|
|
func ContextWithWorker(parent context.Context, worker *workgraph.Worker) context.Context {
|
|
return context.WithValue(parent, workerContextKey, worker)
|
|
}
|
|
|
|
// ContextWithNewWorker is like [ContextWithWorker] except that it internally
|
|
// creates a new worker and associates that with the returned context.
|
|
//
|
|
// This is a good way to create the top-level context needed for first entry
|
|
// into a call graph that relies on the self-reference-detecting functions
|
|
// elsewhere in this package. Those functions will then create other workers
|
|
// as necessary.
|
|
func ContextWithNewWorker(parent context.Context) context.Context {
|
|
return ContextWithWorker(parent, workgraph.NewWorker())
|
|
}
|
|
|
|
// WorkerFromContext returns a pointer to the [workgraph.Worker] associated
|
|
// with the given context, or panics if the context has no worker.
|
|
func WorkerFromContext(ctx context.Context) *workgraph.Worker {
|
|
worker, ok := ctx.Value(workerContextKey).(*workgraph.Worker)
|
|
if !ok {
|
|
panic("no worker handle in this context")
|
|
}
|
|
return worker
|
|
}
|
|
|
|
// ContextWithRequestTracker returns a child of the given context that is
|
|
// associated with the given [RequestTracker].
|
|
//
|
|
// Pass promises derived from the result to other functions in this package that
|
|
// perform self-reference and unresolved request detection to improve the
|
|
// error messages returned when those error situations occur.
|
|
func ContextWithRequestTracker(parent context.Context, tracker RequestTracker) context.Context {
|
|
return context.WithValue(parent, trackerContextKey, tracker)
|
|
}
|
|
|
|
// requestTrackerFromContext returns the request tracker associated with the
|
|
// given context, or nil if there is no request tracker.
|
|
//
|
|
// This is unexported because request trackers are provided by external code
|
|
// but only used by code within this package.
|
|
func requestTrackerFromContext(ctx context.Context) RequestTracker {
|
|
tracker, ok := ctx.Value(trackerContextKey).(RequestTracker)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return tracker
|
|
}
|
|
|
|
type contextKey rune
|
|
|
|
const workerContextKey = contextKey('W')
|
|
const trackerContextKey = contextKey('T')
|