pulumi/sdk/go/property/values.go

215 lines
6.2 KiB
Go

// Copyright 2016-2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The Pulumi value system (formerly resource.PropertyValue)
package property
import (
"fmt"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/archive"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/asset"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/urn"
)
type (
Array = []Value
Map = map[string]Value
Asset = *asset.Asset
Archive = *archive.Archive
)
// Value is an imitable representation of a Pulumi value.
//
// It may represent any type in GoValue. In addition, values may be secret or
// computed. It may have resource dependencies.
//
// The zero value of Value is null.
type Value struct {
isSecret bool
dependencies []urn.URN // the dependencies associated with this value.
// The inner go value for the Value.
//
// Note: null{} is not a valid value for v. null{} should be normalized to nil
// during creation, so that the zero value of Value is bit for bit equivalent to
// `New(Null)`.
v any
}
// GoValue constrains the set of go values that can be contained inside a Value.
//
// Value can also be a null value.
type GoValue interface {
bool | float64 | string | // Primitive types
Array | Map | // Collection types
Asset | Archive | // Pulumi types
ResourceReference | // Resource references
computed | null // marker singletons
}
// New creates a new Value from a GoValue.
func New[T GoValue](goValue T) Value {
return Value{v: normalize(goValue)}
}
func normalize(goValue any) any {
switch goValue := goValue.(type) {
case Array:
if goValue == nil {
return nil
}
case Map:
if goValue == nil {
return nil
}
case Asset:
if goValue == nil {
return nil
}
case Archive:
if goValue == nil {
return nil
}
case null:
return nil
}
return goValue
}
// Any creates a new Value from a GoValue of unknown type. An error is returned if goValue
// is not a member of GoValue.
func Any(goValue any) (Value, error) {
switch goValue := goValue.(type) {
case bool:
return New(goValue), nil
case float64:
return New(goValue), nil
case string:
return New(goValue), nil
case Array:
return New(goValue), nil
case Map:
return New(goValue), nil
case Asset:
return New(goValue), nil
case Archive:
return New(goValue), nil
case ResourceReference:
return New(goValue), nil
case computed:
return New(goValue), nil
case nil, null:
return Value{}, nil
default:
return Value{}, fmt.Errorf("invalid type: %s of type %[1]T", goValue)
}
}
// Computed and Null are marker values of distinct singleton types.
//
// Because the type of the variable is a singleton, it is not possible to mutate these
// values (there is no other value to mutate to).
var (
// Mark a property as an untyped computed value.
Computed computed
// Mark a property as an untyped empty value.
Null null
)
// Singleton marker types.
//
// These types are intentionally private. Users should instead use the available exported
// values.
type (
computed struct{}
null struct{}
)
func is[T GoValue](v Value) bool {
_, ok := v.v.(T)
return ok
}
func as[T GoValue](v Value) T { return v.v.(T) }
func (v Value) IsBool() bool { return is[bool](v) }
func (v Value) IsNumber() bool { return is[float64](v) }
func (v Value) IsString() bool { return is[string](v) }
func (v Value) IsArray() bool { return is[Array](v) }
func (v Value) IsMap() bool { return is[Map](v) }
func (v Value) IsAsset() bool { return is[Asset](v) }
func (v Value) IsArchive() bool { return is[Archive](v) }
func (v Value) IsResourceReference() bool { return is[ResourceReference](v) }
func (v Value) IsNull() bool { return v.v == nil }
func (v Value) IsComputed() bool { return is[computed](v) }
func (v Value) AsBool() bool { return as[bool](v) }
func (v Value) AsNumber() float64 { return as[float64](v) }
func (v Value) AsString() string { return as[string](v) }
func (v Value) AsArray() Array { return as[Array](v) }
func (v Value) AsMap() Map { return as[Map](v) }
func (v Value) AsAsset() Asset { return as[Asset](v) }
func (v Value) AsArchive() Archive { return as[Archive](v) }
func (v Value) AsResourceReference() ResourceReference { return as[ResourceReference](v) }
// Secret returns true if the Value is secret.
//
// It does not check if a contained Value is secret.
func (v Value) Secret() bool { return v.isSecret }
// HasSecrets returns true if the Value or any nested Value is secret.
func (v Value) HasSecrets() bool {
var hasSecret bool
v.visit(func(v Value) bool {
hasSecret = v.isSecret
return !hasSecret
})
return hasSecret
}
// WithSecret copies v where secret is true.
func (v Value) WithSecret(isSecret bool) Value {
v.isSecret = isSecret
return v
}
// HasComputed returns true if the Value or any nested Value is computed.
func (v Value) HasComputed() bool {
var hasComputed bool
v.visit(func(v Value) bool {
hasComputed = v.IsComputed()
return !hasComputed
})
return hasComputed
}
// Dependencies returns the dependency set of v.
func (v Value) Dependencies() []urn.URN { return v.dependencies }
// Set deps as the v.Dependencies() value of the returned Value.
func (v Value) WithDependencies(deps []urn.URN) Value {
v.dependencies = deps
return v
}
// WithGoValue creates a new Value with the inner value newGoValue.
//
// To set to a null or computed value, pass Null or Computed as newGoValue.
func WithGoValue[T GoValue](value Value, newGoValue T) Value {
value.v = New(newGoValue).v
return value
}