1package cty
2
3// Type represents value types within the type system.
4//
5// This is a closed interface type, meaning that only the concrete
6// implementations provided within this package are considered valid.
7type Type struct {
8	typeImpl
9}
10
11type typeImpl interface {
12	// isTypeImpl is a do-nothing method that exists only to express
13	// that a type is an implementation of typeImpl.
14	isTypeImpl() typeImplSigil
15
16	// Equals returns true if the other given Type exactly equals the
17	// receiver Type.
18	Equals(other Type) bool
19
20	// FriendlyName returns a human-friendly *English* name for the given
21	// type.
22	FriendlyName(mode friendlyTypeNameMode) string
23
24	// GoString implements the GoStringer interface from package fmt.
25	GoString() string
26}
27
28// Base implementation of Type to embed into concrete implementations
29// to signal that they are implementations of Type.
30type typeImplSigil struct{}
31
32func (t typeImplSigil) isTypeImpl() typeImplSigil {
33	return typeImplSigil{}
34}
35
36// Equals returns true if the other given Type exactly equals the receiver
37// type.
38func (t Type) Equals(other Type) bool {
39	if t == NilType || other == NilType {
40		return t == other
41	}
42	return t.typeImpl.Equals(other)
43}
44
45// FriendlyName returns a human-friendly *English* name for the given type.
46func (t Type) FriendlyName() string {
47	return t.typeImpl.FriendlyName(friendlyTypeName)
48}
49
50// FriendlyNameForConstraint is similar to FriendlyName except that the
51// result is specialized for describing type _constraints_ rather than types
52// themselves. This is more appropriate when reporting that a particular value
53// does not conform to an expected type constraint.
54//
55// In particular, this function uses the term "any type" to refer to
56// cty.DynamicPseudoType, rather than "dynamic" as returned by FriendlyName.
57func (t Type) FriendlyNameForConstraint() string {
58	return t.typeImpl.FriendlyName(friendlyTypeConstraintName)
59}
60
61// friendlyNameMode is an internal combination of the various FriendlyName*
62// variants that just directly takes a mode, for easy passthrough for
63// recursive name construction.
64func (t Type) friendlyNameMode(mode friendlyTypeNameMode) string {
65	return t.typeImpl.FriendlyName(mode)
66}
67
68// GoString returns a string approximating how the receiver type would be
69// expressed in Go source code.
70func (t Type) GoString() string {
71	if t.typeImpl == nil {
72		return "cty.NilType"
73	}
74
75	return t.typeImpl.GoString()
76}
77
78// NilType is an invalid type used when a function is returning an error
79// and has no useful type to return. It should not be used and any methods
80// called on it will panic.
81var NilType = Type{}
82
83// HasDynamicTypes returns true either if the receiver is itself
84// DynamicPseudoType or if it is a compound type whose descendent elements
85// are DynamicPseudoType.
86func (t Type) HasDynamicTypes() bool {
87	switch {
88	case t == DynamicPseudoType:
89		return true
90	case t.IsPrimitiveType():
91		return false
92	case t.IsCollectionType():
93		return t.ElementType().HasDynamicTypes()
94	case t.IsObjectType():
95		attrTypes := t.AttributeTypes()
96		for _, at := range attrTypes {
97			if at.HasDynamicTypes() {
98				return true
99			}
100		}
101		return false
102	case t.IsTupleType():
103		elemTypes := t.TupleElementTypes()
104		for _, et := range elemTypes {
105			if et.HasDynamicTypes() {
106				return true
107			}
108		}
109		return false
110	case t.IsCapsuleType():
111		return false
112	default:
113		// Should never happen, since above should be exhaustive
114		panic("HasDynamicTypes does not support the given type")
115	}
116}
117
118type friendlyTypeNameMode rune
119
120const (
121	friendlyTypeName           friendlyTypeNameMode = 'N'
122	friendlyTypeConstraintName friendlyTypeNameMode = 'C'
123)
124