]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | package cty |
2 | ||
3 | import ( | |
4 | "fmt" | |
5 | "reflect" | |
6 | ) | |
7 | ||
8 | type capsuleType struct { | |
9 | typeImplSigil | |
10 | Name string | |
11 | GoType reflect.Type | |
12 | } | |
13 | ||
14 | func (t *capsuleType) Equals(other Type) bool { | |
15 | if otherP, ok := other.typeImpl.(*capsuleType); ok { | |
16 | // capsule types compare by pointer identity | |
17 | return otherP == t | |
18 | } | |
19 | return false | |
20 | } | |
21 | ||
107c1cdb | 22 | func (t *capsuleType) FriendlyName(mode friendlyTypeNameMode) string { |
15c0b25d AP |
23 | return t.Name |
24 | } | |
25 | ||
26 | func (t *capsuleType) GoString() string { | |
27 | // To get a useful representation of our native type requires some | |
28 | // shenanigans. | |
29 | victimVal := reflect.Zero(t.GoType) | |
30 | return fmt.Sprintf("cty.Capsule(%q, reflect.TypeOf(%#v))", t.Name, victimVal.Interface()) | |
31 | } | |
32 | ||
33 | // Capsule creates a new Capsule type. | |
34 | // | |
35 | // A Capsule type is a special type that can be used to transport arbitrary | |
36 | // Go native values of a given type through the cty type system. A language | |
37 | // that uses cty as its type system might, for example, provide functions | |
38 | // that return capsule-typed values and then other functions that operate | |
39 | // on those values. | |
40 | // | |
41 | // From cty's perspective, Capsule types have a few interesting characteristics, | |
42 | // described in the following paragraphs. | |
43 | // | |
44 | // Each capsule type has an associated Go native type that it is able to | |
45 | // transport. Capsule types compare by identity, so each call to the | |
46 | // Capsule function creates an entirely-distinct cty Type, even if two calls | |
47 | // use the same native type. | |
48 | // | |
49 | // Each capsule-typed value contains a pointer to a value of the given native | |
50 | // type. A capsule-typed value supports no operations except equality, and | |
51 | // equality is implemented by pointer identity of the encapsulated pointer. | |
52 | // | |
53 | // The given name is used as the new type's "friendly name". This can be any | |
54 | // string in principle, but will usually be a short, all-lowercase name aimed | |
55 | // at users of the embedding language (i.e. not mention Go-specific details) | |
56 | // and will ideally not create ambiguity with any predefined cty type. | |
57 | // | |
58 | // Capsule types are never introduced by any standard cty operation, so a | |
59 | // calling application opts in to including them within its own type system | |
60 | // by creating them and introducing them via its own functions. At that point, | |
61 | // the application is responsible for dealing with any capsule-typed values | |
62 | // that might be returned. | |
63 | func Capsule(name string, nativeType reflect.Type) Type { | |
64 | return Type{ | |
65 | &capsuleType{ | |
66 | Name: name, | |
67 | GoType: nativeType, | |
68 | }, | |
69 | } | |
70 | } | |
71 | ||
72 | // IsCapsuleType returns true if this type is a capsule type, as created | |
73 | // by cty.Capsule . | |
74 | func (t Type) IsCapsuleType() bool { | |
75 | _, ok := t.typeImpl.(*capsuleType) | |
76 | return ok | |
77 | } | |
78 | ||
79 | // EncapsulatedType returns the encapsulated native type of a capsule type, | |
80 | // or panics if the receiver is not a Capsule type. | |
81 | // | |
82 | // Is IsCapsuleType to determine if this method is safe to call. | |
83 | func (t Type) EncapsulatedType() reflect.Type { | |
84 | impl, ok := t.typeImpl.(*capsuleType) | |
85 | if !ok { | |
86 | panic("not a capsule type") | |
87 | } | |
88 | return impl.GoType | |
89 | } |