mirror of https://github.com/pulumi/pulumi.git
119 lines
3.2 KiB
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
|
|
}
|
|
}
|