]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/zclconf/go-cty/cty/type_conform.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / zclconf / go-cty / cty / type_conform.go
CommitLineData
15c0b25d
AP
1package cty
2
3// TestConformance recursively walks the receiver and the given other type and
4// returns nil if the receiver *conforms* to the given type.
5//
6// Type conformance is similar to type equality but has one crucial difference:
7// PseudoTypeDynamic can be used within the given type to represent that
8// *any* type is allowed.
9//
10// If any non-conformities are found, the returned slice will be non-nil and
11// contain at least one error value. It will be nil if the type is entirely
12// conformant.
13//
14// Note that the special behavior of PseudoTypeDynamic is the *only* exception
15// to normal type equality. Calling applications may wish to apply their own
16// automatic conversion logic to the given data structure to create a more
17// liberal notion of conformance to a type.
18//
19// Returned errors are usually (but not always) PathError instances that
20// indicate where in the structure the error was found. If a returned error
21// is of that type then the error message is written for (English-speaking)
22// end-users working within the cty type system, not mentioning any Go-oriented
23// implementation details.
24func (t Type) TestConformance(other Type) []error {
25 path := make(Path, 0)
26 var errs []error
27 testConformance(t, other, path, &errs)
28 return errs
29}
30
31func testConformance(given Type, want Type, path Path, errs *[]error) {
32 if want.Equals(DynamicPseudoType) {
33 // anything goes!
34 return
35 }
36
37 if given.Equals(want) {
38 // Any equal types are always conformant
39 return
40 }
41
42 // The remainder of this function is concerned with detecting
43 // and reporting the specific non-conformance, since we wouldn't
44 // have got here if the types were not divergent.
45 // We treat compound structures as special so that we can report
46 // specifically what is non-conforming, rather than simply returning
47 // the entire type names and letting the user puzzle it out.
48
49 if given.IsObjectType() && want.IsObjectType() {
50 givenAttrs := given.AttributeTypes()
51 wantAttrs := want.AttributeTypes()
52
107c1cdb
ND
53 for k := range givenAttrs {
54 if _, exists := wantAttrs[k]; !exists {
55 *errs = append(
56 *errs,
57 errorf(path, "unsupported attribute %q", k),
58 )
15c0b25d 59 }
107c1cdb
ND
60 }
61 for k := range wantAttrs {
62 if _, exists := givenAttrs[k]; !exists {
63 *errs = append(
64 *errs,
65 errorf(path, "missing required attribute %q", k),
66 )
15c0b25d
AP
67 }
68 }
69
70 path = append(path, nil)
71 pathIdx := len(path) - 1
72
73 for k, wantAttrType := range wantAttrs {
74 if givenAttrType, exists := givenAttrs[k]; exists {
75 path[pathIdx] = GetAttrStep{Name: k}
76 testConformance(givenAttrType, wantAttrType, path, errs)
77 }
78 }
79
80 path = path[0:pathIdx]
81
82 return
83 }
84
85 if given.IsTupleType() && want.IsTupleType() {
86 givenElems := given.TupleElementTypes()
87 wantElems := want.TupleElementTypes()
88
89 if len(givenElems) != len(wantElems) {
90 *errs = append(
91 *errs,
92 errorf(path, "%d elements are required, but got %d", len(wantElems), len(givenElems)),
93 )
94 return
95 }
96
97 path = append(path, nil)
98 pathIdx := len(path) - 1
99
100 for i, wantElemType := range wantElems {
101 givenElemType := givenElems[i]
102 path[pathIdx] = IndexStep{Key: NumberIntVal(int64(i))}
103 testConformance(givenElemType, wantElemType, path, errs)
104 }
105
106 path = path[0:pathIdx]
107
108 return
109 }
110
111 if given.IsListType() && want.IsListType() {
112 path = append(path, IndexStep{Key: UnknownVal(Number)})
113 pathIdx := len(path) - 1
114 testConformance(given.ElementType(), want.ElementType(), path, errs)
115 path = path[0:pathIdx]
116 return
117 }
118
119 if given.IsMapType() && want.IsMapType() {
120 path = append(path, IndexStep{Key: UnknownVal(String)})
121 pathIdx := len(path) - 1
122 testConformance(given.ElementType(), want.ElementType(), path, errs)
123 path = path[0:pathIdx]
124 return
125 }
126
127 if given.IsSetType() && want.IsSetType() {
128 path = append(path, IndexStep{Key: UnknownVal(given.ElementType())})
129 pathIdx := len(path) - 1
130 testConformance(given.ElementType(), want.ElementType(), path, errs)
131 path = path[0:pathIdx]
132 return
133 }
134
135 *errs = append(
136 *errs,
137 errorf(path, "%s required, but received %s", want.FriendlyName(), given.FriendlyName()),
138 )
139}