aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/zclconf/go-cty/cty/convert/conversion.go')
-rw-r--r--vendor/github.com/zclconf/go-cty/cty/convert/conversion.go120
1 files changed, 120 insertions, 0 deletions
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go
new file mode 100644
index 0000000..7bfcc08
--- /dev/null
+++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go
@@ -0,0 +1,120 @@
1package convert
2
3import (
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.
9type conversion func(cty.Value, cty.Path) (cty.Value, error)
10
11func 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 !in.IsKnown() {
21 return cty.UnknownVal(out), nil
22 }
23 if in.IsNull() {
24 // We'll pass through nulls, albeit type converted, and let
25 // the caller deal with whatever handling they want to do in
26 // case null values are considered valid in some applications.
27 return cty.NullVal(out), nil
28 }
29
30 return conv(in, path)
31 }
32}
33
34func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion {
35 switch {
36
37 case out == cty.DynamicPseudoType:
38 // Conversion *to* DynamicPseudoType means that the caller wishes
39 // to allow any type in this position, so we'll produce a do-nothing
40 // conversion that just passes through the value as-is.
41 return dynamicPassthrough
42
43 case unsafe && in == cty.DynamicPseudoType:
44 // Conversion *from* DynamicPseudoType means that we have a value
45 // whose type isn't yet known during type checking. For these we will
46 // assume that conversion will succeed and deal with any errors that
47 // result (which is why we can only do this when "unsafe" is set).
48 return dynamicFixup(out)
49
50 case in.IsPrimitiveType() && out.IsPrimitiveType():
51 conv := primitiveConversionsSafe[in][out]
52 if conv != nil {
53 return conv
54 }
55 if unsafe {
56 return primitiveConversionsUnsafe[in][out]
57 }
58 return nil
59
60 case out.IsListType() && (in.IsListType() || in.IsSetType()):
61 inEty := in.ElementType()
62 outEty := out.ElementType()
63 if inEty.Equals(outEty) {
64 // This indicates that we're converting from list to set with
65 // the same element type, so we don't need an element converter.
66 return conversionCollectionToList(outEty, nil)
67 }
68
69 convEty := getConversion(inEty, outEty, unsafe)
70 if convEty == nil {
71 return nil
72 }
73 return conversionCollectionToList(outEty, convEty)
74
75 case out.IsSetType() && (in.IsListType() || in.IsSetType()):
76 if in.IsListType() && !unsafe {
77 // Conversion from list to map is unsafe because it will lose
78 // information: the ordering will not be preserved, and any
79 // duplicate elements will be conflated.
80 return nil
81 }
82 inEty := in.ElementType()
83 outEty := out.ElementType()
84 convEty := getConversion(inEty, outEty, unsafe)
85 if inEty.Equals(outEty) {
86 // This indicates that we're converting from set to list with
87 // the same element type, so we don't need an element converter.
88 return conversionCollectionToSet(outEty, nil)
89 }
90
91 if convEty == nil {
92 return nil
93 }
94 return conversionCollectionToSet(outEty, convEty)
95
96 case out.IsListType() && in.IsTupleType():
97 outEty := out.ElementType()
98 return conversionTupleToList(in, outEty, unsafe)
99
100 case out.IsMapType() && in.IsObjectType():
101 outEty := out.ElementType()
102 return conversionObjectToMap(in, outEty, unsafe)
103
104 default:
105 return nil
106
107 }
108}
109
110// retConversion wraps a conversion (internal type) so it can be returned
111// as a Conversion (public type).
112func retConversion(conv conversion) Conversion {
113 if conv == nil {
114 return nil
115 }
116
117 return func(in cty.Value) (cty.Value, error) {
118 return conv(in, cty.Path(nil))
119 }
120}