]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/zclconf/go-cty/cty/set_internals.go
deps: github.com/hashicorp/terraform@sdk-v0.11-with-go-modules
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / zclconf / go-cty / cty / set_internals.go
1 package cty
2
3 import (
4 "bytes"
5 "fmt"
6 "hash/crc32"
7 "math/big"
8 "sort"
9 )
10
11 // setRules provides a Rules implementation for the ./set package that
12 // respects the equality rules for cty values of the given type.
13 //
14 // This implementation expects that values added to the set will be
15 // valid internal values for the given Type, which is to say that wrapping
16 // the given value in a Value struct along with the ruleset's type should
17 // produce a valid, working Value.
18 type setRules struct {
19 Type Type
20 }
21
22 func (r setRules) Hash(v interface{}) int {
23 hashBytes := makeSetHashBytes(Value{
24 ty: r.Type,
25 v: v,
26 })
27 return int(crc32.ChecksumIEEE(hashBytes))
28 }
29
30 func (r setRules) Equivalent(v1 interface{}, v2 interface{}) bool {
31 v1v := Value{
32 ty: r.Type,
33 v: v1,
34 }
35 v2v := Value{
36 ty: r.Type,
37 v: v2,
38 }
39
40 eqv := v1v.Equals(v2v)
41
42 // By comparing the result to true we ensure that an Unknown result,
43 // which will result if either value is unknown, will be considered
44 // as non-equivalent. Two unknown values are not equivalent for the
45 // sake of set membership.
46 return eqv.v == true
47 }
48
49 func makeSetHashBytes(val Value) []byte {
50 var buf bytes.Buffer
51 appendSetHashBytes(val, &buf)
52 return buf.Bytes()
53 }
54
55 func appendSetHashBytes(val Value, buf *bytes.Buffer) {
56 // Exactly what bytes we generate here don't matter as long as the following
57 // constraints hold:
58 // - Unknown and null values all generate distinct strings from
59 // each other and from any normal value of the given type.
60 // - The delimiter used to separate items in a compound structure can
61 // never appear literally in any of its elements.
62 // Since we don't support hetrogenous lists we don't need to worry about
63 // collisions between values of different types, apart from
64 // PseudoTypeDynamic.
65 // If in practice we *do* get a collision then it's not a big deal because
66 // the Equivalent function will still distinguish values, but set
67 // performance will be best if we are able to produce a distinct string
68 // for each distinct value, unknown values notwithstanding.
69 if !val.IsKnown() {
70 buf.WriteRune('?')
71 return
72 }
73 if val.IsNull() {
74 buf.WriteRune('~')
75 return
76 }
77
78 switch val.ty {
79 case Number:
80 buf.WriteString(val.v.(*big.Float).String())
81 return
82 case Bool:
83 if val.v.(bool) {
84 buf.WriteRune('T')
85 } else {
86 buf.WriteRune('F')
87 }
88 return
89 case String:
90 buf.WriteString(fmt.Sprintf("%q", val.v.(string)))
91 return
92 }
93
94 if val.ty.IsMapType() {
95 buf.WriteRune('{')
96 val.ForEachElement(func(keyVal, elementVal Value) bool {
97 appendSetHashBytes(keyVal, buf)
98 buf.WriteRune(':')
99 appendSetHashBytes(elementVal, buf)
100 buf.WriteRune(';')
101 return false
102 })
103 buf.WriteRune('}')
104 return
105 }
106
107 if val.ty.IsListType() || val.ty.IsSetType() {
108 buf.WriteRune('[')
109 val.ForEachElement(func(keyVal, elementVal Value) bool {
110 appendSetHashBytes(elementVal, buf)
111 buf.WriteRune(';')
112 return false
113 })
114 buf.WriteRune(']')
115 return
116 }
117
118 if val.ty.IsObjectType() {
119 buf.WriteRune('<')
120 attrNames := make([]string, 0, len(val.ty.AttributeTypes()))
121 for attrName := range val.ty.AttributeTypes() {
122 attrNames = append(attrNames, attrName)
123 }
124 sort.Strings(attrNames)
125 for _, attrName := range attrNames {
126 appendSetHashBytes(val.GetAttr(attrName), buf)
127 buf.WriteRune(';')
128 }
129 buf.WriteRune('>')
130 return
131 }
132
133 if val.ty.IsTupleType() {
134 buf.WriteRune('<')
135 val.ForEachElement(func(keyVal, elementVal Value) bool {
136 appendSetHashBytes(elementVal, buf)
137 buf.WriteRune(';')
138 return false
139 })
140 buf.WriteRune('>')
141 return
142 }
143
144 // should never get down here
145 panic("unsupported type in set hash")
146 }