pulumi/sdk/go/property/equal.go

119 lines
3.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.
package property
type EqualOption func(*eqOpts)
// See the doc comment for Value.Equals for the effect of EqualRelaxComputed.
func EqualRelaxComputed(opts *eqOpts) {
opts.relaxComputed = true
}
type eqOpts struct {
relaxComputed bool
}
// Check if two Values are equal.
//
// There are two corner cases that need to be called out here:
//
// - Secret equality is enforced. That means that:
//
// {"a", secret: false} == {"a", secret: false}
//
// {"a", secret: true} != {"a", secret: false}
//
// {"b", secret: false} != {"c", secret: false}
//
// - Computed value equality has two different modes. By default, it works like Null
// equality: a.IsComputed() => (a.Equals(b) <=> b.IsComputed()) (up to secrets and
// dependencies).
//
// If EqualRelaxComputed is passed, then computed values are considered equal to all
// other values. (up to secrets and dependencies)
func (v Value) Equals(other Value, opts ...EqualOption) bool {
var eqOpts eqOpts
for _, o := range opts {
o(&eqOpts)
}
return v.equals(other, eqOpts)
}
func (v Value) equals(other Value, opts eqOpts) bool {
if v.isSecret != other.isSecret {
return false
}
if len(v.dependencies) != len(other.dependencies) {
return false
}
for i, d := range v.dependencies {
if other.dependencies[i] != d {
return false
}
}
if opts.relaxComputed && (v.IsComputed() || other.IsComputed()) {
return true
}
switch {
case v.IsBool() && other.IsBool():
return v.AsBool() == other.AsBool()
case v.IsNumber() && other.IsNumber():
return v.AsNumber() == other.AsNumber()
case v.IsString() && other.IsString():
return v.AsString() == other.AsString()
case v.IsArray() && other.IsArray():
a1, a2 := v.AsArray(), other.AsArray()
if len(a1) != len(a2) {
return false
}
for i := range a1 {
if !a1[i].equals(a2[i], opts) {
return false
}
}
return true
case v.IsMap() && other.IsMap():
m1, m2 := v.AsMap(), other.AsMap()
if len(m1) != len(m2) {
return false
}
for k, v1 := range m1 {
v2, ok := m2[k]
if !ok || !v1.equals(v2, opts) {
return false
}
}
return true
case v.IsAsset() && other.IsAsset():
a1, a2 := v.AsAsset(), other.AsAsset()
return a1.Equals(a2)
case v.IsArchive() && other.IsArchive():
a1, a2 := v.AsArchive(), other.AsArchive()
return a1.Equals(a2)
case v.IsResourceReference() && other.IsResourceReference():
r1, r2 := v.AsResourceReference(), other.AsResourceReference()
return r1.Equal(r2)
case v.IsNull() && other.IsNull():
return true
case v.IsComputed() && other.IsComputed():
return true
default:
return false
}
}