3 // Value represents a value of a particular type, and is the interface by
4 // which operations are executed on typed values.
6 // Value has two different classes of method. Operation methods stay entirely
7 // within the type system (methods accept and return Value instances) and
8 // are intended for use in implementing a language in terms of cty, while
9 // integration methods either enter or leave the type system, working with
10 // native Go values. Operation methods are guaranteed to support all of the
11 // expected short-circuit behavior for unknown and dynamic values, while
12 // integration methods may not.
14 // The philosophy for the operations API is that it's the caller's
15 // responsibility to ensure that the given types and values satisfy the
16 // specified invariants during a separate type check, so that the caller is
17 // able to return errors to its user from the application's own perspective.
19 // Consequently the design of these methods assumes such checks have already
20 // been done and panics if any invariants turn out not to be satisfied. These
21 // panic errors are not intended to be handled, but rather indicate a bug in
22 // the calling application that should be fixed with more checks prior to
23 // executing operations.
25 // A related consequence of this philosophy is that no automatic type
26 // conversions are done. If a method specifies that its argument must be
27 // number then it's the caller's responsibility to do that conversion before
28 // the call, thus allowing the application to have more constrained conversion
29 // rules than are offered by the built-in converter where necessary.
35 // Type returns the type of the value.
36 func (val Value) Type() Type {
40 // IsKnown returns true if the value is known. That is, if it is not
41 // the result of the unknown value constructor Unknown(...), and is not
42 // the result of an operation on another unknown value.
44 // Unknown values are only produced either directly or as a result of
45 // operating on other unknown values, and so an application that never
46 // introduces Unknown values can be guaranteed to never receive any either.
47 func (val Value) IsKnown() bool {
48 return val.v != unknown
51 // IsNull returns true if the value is null. Values of any type can be
52 // null, but any operations on a null value will panic. No operation ever
53 // produces null, so an application that never introduces Null values can
54 // be guaranteed to never receive any either.
55 func (val Value) IsNull() bool {
59 // NilVal is an invalid Value that can be used as a placeholder when returning
60 // with an error from a function that returns (Value, error).
62 // NilVal is *not* a valid error and so no operations may be performed on it.
63 // Any attempt to use it will result in a panic.
65 // This should not be confused with the idea of a Null value, as returned by
66 // NullVal. NilVal is a nil within the *Go* type system, and is invalid in
67 // the cty type system. Null values *do* exist in the cty type system.
69 ty: Type{typeImpl: nil},
73 // IsWhollyKnown is an extension of IsKnown that also recursively checks
74 // inside collections and structures to see if there are any nested unknown
76 func (val Value) IsWhollyKnown() bool {
82 // Can't recurse into a null, so we're done
87 case val.CanIterateElements():
88 for it := val.ElementIterator(); it.Next(); {
90 if !ev.IsWhollyKnown() {