// 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 }