-
Notifications
You must be signed in to change notification settings - Fork 50
/
Copy pathtype.go
272 lines (235 loc) · 8.95 KB
/
type.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
package schema
import (
"github.com/ipld/go-ipld-prime/datamodel"
)
type TypeName = string
// typesystem.Type is an union interface; each of the `Type*` concrete types
// in this package are one of its members.
//
// Specifically,
//
// TypeBool
// TypeString
// TypeBytes
// TypeInt
// TypeFloat
// TypeMap
// TypeList
// TypeLink
// TypeUnion
// TypeStruct
// TypeEnum
//
// are all of the kinds of Type.
//
// This is a closed union; you can switch upon the above members without
// including a default case. The membership is closed by the unexported
// '_Type' method; you may use the BurntSushi/go-sumtype tool to check
// your switches for completeness.
//
// Many interesting properties of each Type are only defined for that specific
// type, so it's typical to use a type switch to handle each type of Type.
// (Your humble author is truly sorry for the word-mash that results from
// attempting to describe the types that describe the typesystem.Type.)
//
// For example, to inspect the kind of fields in a struct: you might
// cast a `Type` interface into `TypeStruct`, and then the `Fields()` on
// that `TypeStruct` can be inspected. (`Fields()` isn't defined for any
// other kind of Type.)
type Type interface {
// Unexported marker method to force the union closed.
// Also used to set the internal pointer back to the universe its part of.
_Type(*TypeSystem)
// Returns a pointer to the TypeSystem this Type is a member of.
TypeSystem() *TypeSystem
// Returns the string name of the Type. This name is unique within the
// universe this type is a member of, *unless* this type is Anonymous,
// in which case a string describing the type will still be returned, but
// that string will not be required to be unique.
Name() TypeName
// Returns the TypeKind of this Type.
//
// The returned value is a 1:1 association with which of the concrete
// "schema.Type*" structs this interface can be cast to.
//
// Note that a schema.TypeKind is a different enum than datamodel.Kind;
// and furthermore, there's no strict relationship between them.
// schema.TypedNode values can be described by *two* distinct Kinds:
// one which describes how the Node itself will act,
// and another which describes how the Node presents for serialization.
// For some combinations of Type and representation strategy, one or both
// of the Kinds can be determined statically; but not always:
// it can sometimes be necessary to inspect the value quite concretely
// (e.g., `schema.TypedNode{}.Representation().Kind()`) in order to find
// out exactly how a node will be serialized! This is because some types
// can vary in representation kind based on their value (specifically,
// kinded-representation unions have this property).
TypeKind() TypeKind
// RepresentationBehavior returns a description of how the representation
// of this type will behave in terms of the IPLD Data Model.
// This property varies based on the representation strategy of a type.
//
// In one case, the representation behavior cannot be known statically,
// and varies based on the data: kinded unions have this trait.
//
// This property is used by kinded unions, which require that their members
// all have distinct representation behavior.
// (It follows that a kinded union cannot have another kinded union as a member.)
//
// You may also be interested in a related property that might have been called "TypeBehavior".
// However, this method doesn't exist, because it's a deterministic property of `TypeKind()`!
// You can use `TypeKind.ActsLike()` to get type-level behavioral information.
RepresentationBehavior() datamodel.Kind
}
var (
_ Type = &TypeBool{}
_ Type = &TypeString{}
_ Type = &TypeBytes{}
_ Type = &TypeInt{}
_ Type = &TypeFloat{}
_ Type = &TypeAny{}
_ Type = &TypeMap{}
_ Type = &TypeList{}
_ Type = &TypeLink{}
_ Type = &TypeUnion{}
_ Type = &TypeStruct{}
_ Type = &TypeEnum{}
)
type typeBase struct {
name TypeName
universe *TypeSystem
}
type TypeBool struct {
typeBase
}
type TypeString struct {
typeBase
}
type TypeBytes struct {
typeBase
}
type TypeInt struct {
typeBase
}
type TypeFloat struct {
typeBase
}
type TypeAny struct {
typeBase
}
type TypeMap struct {
typeBase
anonymous bool
keyType TypeName // must be Kind==string (e.g. Type==String|Enum).
valueType TypeName
valueNullable bool
}
type TypeList struct {
typeBase
anonymous bool
valueType TypeName
valueNullable bool
}
type TypeLink struct {
typeBase
referencedType TypeName
hasReferencedType bool
// ...?
}
type TypeUnion struct {
typeBase
// Members are listed in the order they appear in the schema.
// To find the discriminant info, you must look inside the representation; they all contain a 'table' of some kind in which the member types are the values.
// Note that multiple appearances of the same type as distinct members of the union is not possible.
// While we could do this... A: that's... odd, and nearly never called for; B: not possible with kinded mode; C: imagine the golang-native type switch! it's impossible.
// We rely on this clarity in many ways: most visibly, the type-level Node implementation for a union always uses the type names as if they were map keys! This behavior is consistent for all union representations.
members []TypeName
representation UnionRepresentation
}
type UnionRepresentation interface{ _UnionRepresentation() }
func (UnionRepresentation_Keyed) _UnionRepresentation() {}
func (UnionRepresentation_Kinded) _UnionRepresentation() {}
func (UnionRepresentation_Envelope) _UnionRepresentation() {}
func (UnionRepresentation_Inline) _UnionRepresentation() {}
func (UnionRepresentation_Stringprefix) _UnionRepresentation() {}
// A bunch of these tables in union representation might be easier to use if flipped;
// we almost always index into them by type (since that's what we have an ordered list of);
// and they're unique in both directions, so it's equally valid either way.
// The order they're currently written in matches the serial form in the schema AST.
type UnionRepresentation_Keyed struct {
table map[string]TypeName // key is user-defined freetext
}
type UnionRepresentation_Kinded struct {
table map[datamodel.Kind]TypeName
}
//lint:ignore U1000 implementation TODO
type UnionRepresentation_Envelope struct {
discriminantKey string
contentKey string
table map[string]TypeName // key is user-defined freetext
}
//lint:ignore U1000 implementation TODO
type UnionRepresentation_Inline struct {
discriminantKey string
table map[string]TypeName // key is user-defined freetext
}
type UnionRepresentation_Stringprefix struct {
delim string
table map[string]TypeName // key is user-defined freetext
}
type TypeStruct struct {
typeBase
// n.b. `Fields` is an (order-preserving!) map in the schema-schema;
// but it's a list here, with the keys denormalized into the value,
// because that's typically how we use it.
fields []StructField
fieldsMap map[string]StructField // same content, indexed for lookup.
representation StructRepresentation
}
type StructField struct {
parent *TypeStruct
name string
typ TypeName
optional bool
nullable bool
}
type StructRepresentation interface{ _StructRepresentation() }
func (StructRepresentation_Map) _StructRepresentation() {}
func (StructRepresentation_Tuple) _StructRepresentation() {}
func (StructRepresentation_ListPairs) _StructRepresentation() {}
func (StructRepresentation_StringPairs) _StructRepresentation() {}
func (StructRepresentation_Stringjoin) _StructRepresentation() {}
type StructRepresentation_Map struct {
renames map[string]string
implicits map[string]ImplicitValue
}
type StructRepresentation_Tuple struct{}
type StructRepresentation_ListPairs struct{}
//lint:ignore U1000 implementation TODO
type StructRepresentation_StringPairs struct{ sep1, sep2 string }
type StructRepresentation_Stringjoin struct{ sep string }
type TypeEnum struct {
typeBase
members []string
representation EnumRepresentation
}
type EnumRepresentation interface{ _EnumRepresentation() }
func (EnumRepresentation_String) _EnumRepresentation() {}
func (EnumRepresentation_Int) _EnumRepresentation() {}
type EnumRepresentation_String map[string]string
type EnumRepresentation_Int map[string]int
// ImplicitValue is an sum type holding values that are implicits.
// It's not an 'Any' value because it can't be recursive
// (or to be slightly more specific, it can be one of the recursive kinds,
// but if so, only its empty value is valid here).
type ImplicitValue interface{ _ImplicitValue() }
func (ImplicitValue_EmptyList) _ImplicitValue() {}
func (ImplicitValue_EmptyMap) _ImplicitValue() {}
func (ImplicitValue_String) _ImplicitValue() {}
func (ImplicitValue_Int) _ImplicitValue() {}
func (ImplicitValue_Bool) _ImplicitValue() {}
type ImplicitValue_EmptyList struct{}
type ImplicitValue_EmptyMap struct{}
type ImplicitValue_String string
type ImplicitValue_Int int
type ImplicitValue_Bool bool