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