]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/zclconf/go-cty/cty/convert/conversion.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / zclconf / go-cty / cty / convert / conversion.go
1 package convert
2
3 import (
4 "github.com/zclconf/go-cty/cty"
5 )
6
7 // conversion is an internal variant of Conversion that carries around
8 // a cty.Path to be used in error responses.
9 type conversion func(cty.Value, cty.Path) (cty.Value, error)
10
11 func getConversion(in cty.Type, out cty.Type, unsafe bool) conversion {
12 conv := getConversionKnown(in, out, unsafe)
13 if conv == nil {
14 return nil
15 }
16
17 // Wrap the conversion in some standard checks that we don't want to
18 // have to repeat in every conversion function.
19 return func(in cty.Value, path cty.Path) (cty.Value, error) {
20 if out == cty.DynamicPseudoType {
21 // Conversion to DynamicPseudoType always just passes through verbatim.
22 return in, nil
23 }
24 if !in.IsKnown() {
25 return cty.UnknownVal(out), nil
26 }
27 if in.IsNull() {
28 // We'll pass through nulls, albeit type converted, and let
29 // the caller deal with whatever handling they want to do in
30 // case null values are considered valid in some applications.
31 return cty.NullVal(out), nil
32 }
33
34 return conv(in, path)
35 }
36 }
37
38 func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion {
39 switch {
40
41 case out == cty.DynamicPseudoType:
42 // Conversion *to* DynamicPseudoType means that the caller wishes
43 // to allow any type in this position, so we'll produce a do-nothing
44 // conversion that just passes through the value as-is.
45 return dynamicPassthrough
46
47 case unsafe && in == cty.DynamicPseudoType:
48 // Conversion *from* DynamicPseudoType means that we have a value
49 // whose type isn't yet known during type checking. For these we will
50 // assume that conversion will succeed and deal with any errors that
51 // result (which is why we can only do this when "unsafe" is set).
52 return dynamicFixup(out)
53
54 case in.IsPrimitiveType() && out.IsPrimitiveType():
55 conv := primitiveConversionsSafe[in][out]
56 if conv != nil {
57 return conv
58 }
59 if unsafe {
60 return primitiveConversionsUnsafe[in][out]
61 }
62 return nil
63
64 case out.IsObjectType() && in.IsObjectType():
65 return conversionObjectToObject(in, out, unsafe)
66
67 case out.IsTupleType() && in.IsTupleType():
68 return conversionTupleToTuple(in, out, unsafe)
69
70 case out.IsListType() && (in.IsListType() || in.IsSetType()):
71 inEty := in.ElementType()
72 outEty := out.ElementType()
73 if inEty.Equals(outEty) {
74 // This indicates that we're converting from list to set with
75 // the same element type, so we don't need an element converter.
76 return conversionCollectionToList(outEty, nil)
77 }
78
79 convEty := getConversion(inEty, outEty, unsafe)
80 if convEty == nil {
81 return nil
82 }
83 return conversionCollectionToList(outEty, convEty)
84
85 case out.IsSetType() && (in.IsListType() || in.IsSetType()):
86 if in.IsListType() && !unsafe {
87 // Conversion from list to map is unsafe because it will lose
88 // information: the ordering will not be preserved, and any
89 // duplicate elements will be conflated.
90 return nil
91 }
92 inEty := in.ElementType()
93 outEty := out.ElementType()
94 convEty := getConversion(inEty, outEty, unsafe)
95 if inEty.Equals(outEty) {
96 // This indicates that we're converting from set to list with
97 // the same element type, so we don't need an element converter.
98 return conversionCollectionToSet(outEty, nil)
99 }
100
101 if convEty == nil {
102 return nil
103 }
104 return conversionCollectionToSet(outEty, convEty)
105
106 case out.IsMapType() && in.IsMapType():
107 inEty := in.ElementType()
108 outEty := out.ElementType()
109 convEty := getConversion(inEty, outEty, unsafe)
110 if convEty == nil {
111 return nil
112 }
113 return conversionCollectionToMap(outEty, convEty)
114
115 case out.IsListType() && in.IsTupleType():
116 outEty := out.ElementType()
117 return conversionTupleToList(in, outEty, unsafe)
118
119 case out.IsSetType() && in.IsTupleType():
120 outEty := out.ElementType()
121 return conversionTupleToSet(in, outEty, unsafe)
122
123 case out.IsMapType() && in.IsObjectType():
124 outEty := out.ElementType()
125 return conversionObjectToMap(in, outEty, unsafe)
126
127 default:
128 return nil
129
130 }
131 }
132
133 // retConversion wraps a conversion (internal type) so it can be returned
134 // as a Conversion (public type).
135 func retConversion(conv conversion) Conversion {
136 if conv == nil {
137 return nil
138 }
139
140 return func(in cty.Value) (cty.Value, error) {
141 return conv(in, cty.Path(nil))
142 }
143 }