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