github.com/ipld/go-ipld-prime@v0.21.0/schema/dmt/schema.go (about)

     1  package schemadmt
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/ipld/go-ipld-prime/datamodel"
     7  	"github.com/ipld/go-ipld-prime/node/bindnode"
     8  	"github.com/ipld/go-ipld-prime/schema"
     9  )
    10  
    11  // Prototypes contains some schema.TypedPrototype values which match
    12  // the IPLD schema-schema -- that is, the schema that describes IPLD schemas.
    13  // These prototypes create an in-memory representation that is backed by
    14  // structs in this package and bindnode.
    15  var Prototypes struct {
    16  	Schema schema.TypedPrototype
    17  }
    18  
    19  //go:generate go run -tags=schemadmtgen gen.go
    20  
    21  // TypeSystem is a compiled equivalent of the IPLD schema-schema -- that is, the schema that describes IPLD schemas.
    22  //
    23  // The IPLD schema-schema can be found at https://ipld.io/specs/schemas/schema-schema.ipldsch .
    24  var TypeSystem schema.TypeSystem
    25  
    26  // In this init function, we manually create a type system that *matches* the IPLD schema-schema.
    27  // This manual work is unfortunate, and also must be kept in-sync manually,
    28  // but is important because breaks a cyclic dependency --
    29  // we use the compiled schema-schema produced by this to parse other schema documents.
    30  // We would also use it to parse... the IPLD schema-schema... if that weren't a cyclic dependency.
    31  func init() {
    32  	var ts schema.TypeSystem
    33  	ts.Init()
    34  
    35  	// I've elided all references to Advancedlayouts stuff for the moment.
    36  	// (Not because it's particularly hard or problematic; I just want to draw a slightly smaller circle first.)
    37  
    38  	// Prelude
    39  	ts.Accumulate(schema.SpawnString("String"))
    40  	ts.Accumulate(schema.SpawnBool("Bool"))
    41  	ts.Accumulate(schema.SpawnInt("Int"))
    42  	ts.Accumulate(schema.SpawnFloat("Float"))
    43  	ts.Accumulate(schema.SpawnBytes("Bytes"))
    44  
    45  	// Schema-schema!
    46  	// In the same order as the spec's ipldsch file.
    47  	// Note that ADL stuff is excluded for now, as per above.
    48  	ts.Accumulate(schema.SpawnString("TypeName"))
    49  	ts.Accumulate(schema.SpawnStruct("Schema",
    50  		[]schema.StructField{
    51  			schema.SpawnStructField("types", "Map__TypeName__TypeDefn", false, false),
    52  			// also: `advanced AdvancedDataLayoutMap`, but as commented above, we'll pursue this later.
    53  		},
    54  		schema.StructRepresentation_Map{},
    55  	))
    56  	ts.Accumulate(schema.SpawnMap("Map__TypeName__TypeDefn",
    57  		"TypeName", "TypeDefn", false,
    58  	))
    59  	ts.Accumulate(schema.SpawnUnion("TypeDefn",
    60  		[]schema.TypeName{
    61  			"TypeDefnBool",
    62  			"TypeDefnString",
    63  			"TypeDefnBytes",
    64  			"TypeDefnInt",
    65  			"TypeDefnFloat",
    66  			"TypeDefnMap",
    67  			"TypeDefnList",
    68  			"TypeDefnLink",
    69  			"TypeDefnUnion",
    70  			"TypeDefnStruct",
    71  			"TypeDefnEnum",
    72  			"TypeDefnUnit",
    73  			"TypeDefnAny",
    74  			"TypeDefnCopy",
    75  		},
    76  		// TODO: spec uses inline repr.
    77  		schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
    78  			"bool":   "TypeDefnBool",
    79  			"string": "TypeDefnString",
    80  			"bytes":  "TypeDefnBytes",
    81  			"int":    "TypeDefnInt",
    82  			"float":  "TypeDefnFloat",
    83  			"map":    "TypeDefnMap",
    84  			"list":   "TypeDefnList",
    85  			"link":   "TypeDefnLink",
    86  			"union":  "TypeDefnUnion",
    87  			"struct": "TypeDefnStruct",
    88  			"enum":   "TypeDefnEnum",
    89  			"unit":   "TypeDefnUnit",
    90  			"any":    "TypeDefnAny",
    91  			"copy":   "TypeDefnCopy",
    92  		}),
    93  	))
    94  	ts.Accumulate(schema.SpawnUnion("TypeNameOrInlineDefn",
    95  		[]schema.TypeName{
    96  			"TypeName",
    97  			"InlineDefn",
    98  		},
    99  		schema.SpawnUnionRepresentationKinded(map[datamodel.Kind]schema.TypeName{
   100  			datamodel.Kind_String: "TypeName",
   101  			datamodel.Kind_Map:    "InlineDefn",
   102  		}),
   103  	))
   104  	ts.Accumulate(schema.SpawnUnion("InlineDefn",
   105  		[]schema.TypeName{
   106  			"TypeDefnMap",
   107  			"TypeDefnList",
   108  			"TypeDefnLink",
   109  		},
   110  		schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
   111  			"map":  "TypeDefnMap",
   112  			"list": "TypeDefnList",
   113  			"link": "TypeDefnLink",
   114  		}),
   115  	))
   116  	ts.Accumulate(schema.SpawnStruct("TypeDefnBool",
   117  		[]schema.StructField{},
   118  		schema.StructRepresentation_Map{},
   119  	))
   120  	ts.Accumulate(schema.SpawnStruct("TypeDefnString",
   121  		[]schema.StructField{},
   122  		schema.StructRepresentation_Map{},
   123  	))
   124  	ts.Accumulate(schema.SpawnStruct("TypeDefnBytes",
   125  		[]schema.StructField{},
   126  		// No BytesRepresentation, since we omit ADL stuff.
   127  		schema.StructRepresentation_Map{},
   128  	))
   129  	ts.Accumulate(schema.SpawnStruct("TypeDefnInt",
   130  		[]schema.StructField{},
   131  		schema.StructRepresentation_Map{},
   132  	))
   133  	ts.Accumulate(schema.SpawnStruct("TypeDefnFloat",
   134  		[]schema.StructField{},
   135  		schema.StructRepresentation_Map{},
   136  	))
   137  	ts.Accumulate(schema.SpawnStruct("TypeDefnMap",
   138  		[]schema.StructField{
   139  			schema.SpawnStructField("keyType", "TypeName", false, false),
   140  			schema.SpawnStructField("valueType", "TypeNameOrInlineDefn", false, false),
   141  			schema.SpawnStructField("valueNullable", "Bool", true, false),               // TODO: wants to use the "implicit" feature, but not supported yet
   142  			schema.SpawnStructField("representation", "MapRepresentation", true, false), // XXXXXX
   143  		},
   144  		schema.StructRepresentation_Map{},
   145  	))
   146  	ts.Accumulate(schema.SpawnUnion("MapRepresentation",
   147  		[]schema.TypeName{
   148  			"MapRepresentation_Map",
   149  			"MapRepresentation_Stringpairs",
   150  			"MapRepresentation_Listpairs",
   151  		},
   152  		schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
   153  			"map":         "MapRepresentation_Map",
   154  			"stringpairs": "MapRepresentation_Stringpairs",
   155  			"listpairs":   "MapRepresentation_Listpairs",
   156  		}),
   157  	))
   158  	ts.Accumulate(schema.SpawnStruct("MapRepresentation_Map",
   159  		[]schema.StructField{},
   160  		schema.StructRepresentation_Map{},
   161  	))
   162  	ts.Accumulate(schema.SpawnStruct("MapRepresentation_Stringpairs",
   163  		[]schema.StructField{
   164  			schema.SpawnStructField("innerDelim", "String", false, false),
   165  			schema.SpawnStructField("entryDelim", "String", false, false),
   166  		},
   167  		schema.StructRepresentation_Map{},
   168  	))
   169  	ts.Accumulate(schema.SpawnStruct("MapRepresentation_Listpairs",
   170  		[]schema.StructField{},
   171  		schema.StructRepresentation_Map{},
   172  	))
   173  	ts.Accumulate(schema.SpawnStruct("TypeDefnList",
   174  		[]schema.StructField{
   175  			schema.SpawnStructField("valueType", "TypeNameOrInlineDefn", false, false),
   176  			schema.SpawnStructField("valueNullable", "Bool", true, false),                // TODO: wants to use the "implicit" feature, but not supported yet
   177  			schema.SpawnStructField("representation", "ListRepresentation", true, false), // XXXXXX
   178  		},
   179  		schema.StructRepresentation_Map{},
   180  	))
   181  	ts.Accumulate(schema.SpawnUnion("ListRepresentation",
   182  		[]schema.TypeName{
   183  			"ListRepresentation_List",
   184  		},
   185  		schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
   186  			"list": "ListRepresentation_List",
   187  		}),
   188  	))
   189  	ts.Accumulate(schema.SpawnStruct("ListRepresentation_List",
   190  		[]schema.StructField{},
   191  		schema.StructRepresentation_Map{},
   192  	))
   193  	ts.Accumulate(schema.SpawnStruct("TypeDefnUnion",
   194  		[]schema.StructField{
   195  			// n.b. we could conceivably allow TypeNameOrInlineDefn here rather than just TypeName.  but... we'd rather not: imagine what that means about the type-level behavior of the union: the name munge for the anonymous type would suddenly become load-bearing.  would rather not.
   196  			schema.SpawnStructField("members", "List__UnionMember", false, false),
   197  			schema.SpawnStructField("representation", "UnionRepresentation", false, false),
   198  		},
   199  		schema.StructRepresentation_Map{},
   200  	))
   201  	ts.Accumulate(schema.SpawnList("List__UnionMember",
   202  		"UnionMember", false,
   203  	))
   204  	ts.Accumulate(schema.SpawnUnion("UnionMember",
   205  		[]schema.TypeName{
   206  			"TypeName",
   207  			"UnionMemberInlineDefn",
   208  		},
   209  		schema.SpawnUnionRepresentationKinded(map[datamodel.Kind]schema.TypeName{
   210  			datamodel.Kind_String: "TypeName",
   211  			datamodel.Kind_Map:    "UnionMemberInlineDefn",
   212  		}),
   213  	))
   214  	ts.Accumulate(schema.SpawnUnion("UnionMemberInlineDefn",
   215  		[]schema.TypeName{
   216  			"TypeDefnLink",
   217  		},
   218  		schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
   219  			"link": "TypeDefnLink",
   220  		}),
   221  	))
   222  	ts.Accumulate(schema.SpawnList("List__TypeName", // todo: this is a slight hack: should be an anon inside TypeDefnUnion.members.
   223  		"TypeName", false,
   224  	))
   225  	ts.Accumulate(schema.SpawnStruct("TypeDefnLink",
   226  		[]schema.StructField{
   227  			schema.SpawnStructField("expectedType", "TypeName", true, false), // todo: this uses an implicit with a value of 'any' in the schema-schema, but that's been questioned before.  maybe it should simply be an optional.
   228  		},
   229  		schema.StructRepresentation_Map{},
   230  	))
   231  	ts.Accumulate(schema.SpawnUnion("UnionRepresentation",
   232  		[]schema.TypeName{
   233  			"UnionRepresentation_Kinded",
   234  			"UnionRepresentation_Keyed",
   235  			"UnionRepresentation_Envelope",
   236  			"UnionRepresentation_Inline",
   237  			"UnionRepresentation_StringPrefix",
   238  			"UnionRepresentation_BytesPrefix",
   239  		},
   240  		schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
   241  			"kinded":       "UnionRepresentation_Kinded",
   242  			"keyed":        "UnionRepresentation_Keyed",
   243  			"envelope":     "UnionRepresentation_Envelope",
   244  			"inline":       "UnionRepresentation_Inline",
   245  			"stringprefix": "UnionRepresentation_StringPrefix",
   246  			"byteprefix":   "UnionRepresentation_BytesPrefix",
   247  		}),
   248  	))
   249  	ts.Accumulate(schema.SpawnMap("UnionRepresentation_Kinded",
   250  		"RepresentationKind", "UnionMember", false,
   251  	))
   252  	ts.Accumulate(schema.SpawnMap("UnionRepresentation_Keyed",
   253  		"String", "UnionMember", false,
   254  	))
   255  	ts.Accumulate(schema.SpawnMap("Map__String__UnionMember",
   256  		"TypeName", "TypeDefn", false,
   257  	))
   258  	ts.Accumulate(schema.SpawnStruct("UnionRepresentation_Envelope",
   259  		[]schema.StructField{
   260  			schema.SpawnStructField("discriminantKey", "String", false, false),
   261  			schema.SpawnStructField("contentKey", "String", false, false),
   262  			schema.SpawnStructField("discriminantTable", "Map__String__UnionMember", false, false),
   263  		},
   264  		schema.StructRepresentation_Map{},
   265  	))
   266  	ts.Accumulate(schema.SpawnStruct("UnionRepresentation_Inline",
   267  		[]schema.StructField{
   268  			schema.SpawnStructField("discriminantKey", "String", false, false),
   269  			schema.SpawnStructField("discriminantTable", "Map__String__TypeName", false, false),
   270  		},
   271  		schema.StructRepresentation_Map{},
   272  	))
   273  	ts.Accumulate(schema.SpawnStruct("UnionRepresentation_StringPrefix",
   274  		[]schema.StructField{
   275  			schema.SpawnStructField("prefixes", "Map__String__TypeName", false, false),
   276  		},
   277  		schema.StructRepresentation_Map{},
   278  	))
   279  	ts.Accumulate(schema.SpawnStruct("UnionRepresentation_BytesPrefix",
   280  		[]schema.StructField{
   281  			schema.SpawnStructField("prefixes", "Map__HexString__TypeName", false, false),
   282  		},
   283  		schema.StructRepresentation_Map{},
   284  	))
   285  	ts.Accumulate(schema.SpawnMap("Map__HexString__TypeName",
   286  		"String", "TypeName", false,
   287  	))
   288  	ts.Accumulate(schema.SpawnString("HexString"))
   289  	ts.Accumulate(schema.SpawnMap("Map__String__TypeName",
   290  		"String", "TypeName", false,
   291  	))
   292  	ts.Accumulate(schema.SpawnMap("Map__TypeName__Int",
   293  		"String", "Int", false,
   294  	))
   295  	ts.Accumulate(schema.SpawnString("RepresentationKind")) // todo: RepresentationKind is supposed to be an enum, but we're puting it to a string atm.
   296  	ts.Accumulate(schema.SpawnStruct("TypeDefnStruct",
   297  		[]schema.StructField{
   298  			schema.SpawnStructField("fields", "Map__FieldName__StructField", false, false), // todo: dodging inline defn's again.
   299  			schema.SpawnStructField("representation", "StructRepresentation", false, false),
   300  		},
   301  		schema.StructRepresentation_Map{},
   302  	))
   303  	ts.Accumulate(schema.SpawnMap("Map__FieldName__StructField",
   304  		"FieldName", "StructField", false,
   305  	))
   306  	ts.Accumulate(schema.SpawnString("FieldName"))
   307  	ts.Accumulate(schema.SpawnStruct("StructField",
   308  		[]schema.StructField{
   309  			schema.SpawnStructField("type", "TypeNameOrInlineDefn", false, false),
   310  			schema.SpawnStructField("optional", "Bool", true, false), // todo: wants to use the "implicit" feature, but not supported yet
   311  			schema.SpawnStructField("nullable", "Bool", true, false), // todo: wants to use the "implicit" feature, but not supported yet
   312  		},
   313  		schema.StructRepresentation_Map{},
   314  	))
   315  	ts.Accumulate(schema.SpawnUnion("StructRepresentation",
   316  		[]schema.TypeName{
   317  			"StructRepresentation_Map",
   318  			"StructRepresentation_Tuple",
   319  			"StructRepresentation_Stringpairs",
   320  			"StructRepresentation_Stringjoin",
   321  			"StructRepresentation_Listpairs",
   322  		},
   323  		schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
   324  			"map":         "StructRepresentation_Map",
   325  			"tuple":       "StructRepresentation_Tuple",
   326  			"stringpairs": "StructRepresentation_Stringpairs",
   327  			"stringjoin":  "StructRepresentation_Stringjoin",
   328  			"listpairs":   "StructRepresentation_Listpairs",
   329  		}),
   330  	))
   331  	ts.Accumulate(schema.SpawnStruct("StructRepresentation_Map",
   332  		[]schema.StructField{
   333  			schema.SpawnStructField("fields", "Map__FieldName__StructRepresentation_Map_FieldDetails", true, false), // todo: dodging inline defn's again.
   334  		},
   335  		schema.StructRepresentation_Map{},
   336  	))
   337  	ts.Accumulate(schema.SpawnMap("Map__FieldName__StructRepresentation_Map_FieldDetails",
   338  		"FieldName", "StructRepresentation_Map_FieldDetails", false,
   339  	))
   340  	ts.Accumulate(schema.SpawnStruct("StructRepresentation_Map_FieldDetails",
   341  		[]schema.StructField{
   342  			schema.SpawnStructField("rename", "String", true, false),
   343  			schema.SpawnStructField("implicit", "AnyScalar", true, false),
   344  		},
   345  		schema.StructRepresentation_Map{},
   346  	))
   347  	ts.Accumulate(schema.SpawnStruct("StructRepresentation_Tuple",
   348  		[]schema.StructField{
   349  			schema.SpawnStructField("fieldOrder", "List__FieldName", true, false), // todo: dodging inline defn's again.
   350  		},
   351  		schema.StructRepresentation_Map{},
   352  	))
   353  	ts.Accumulate(schema.SpawnList("List__FieldName",
   354  		"FieldName", false,
   355  	))
   356  	ts.Accumulate(schema.SpawnStruct("StructRepresentation_Stringpairs",
   357  		[]schema.StructField{
   358  			schema.SpawnStructField("innerDelim", "String", false, false),
   359  			schema.SpawnStructField("entryDelim", "String", false, false),
   360  		},
   361  		schema.StructRepresentation_Map{},
   362  	))
   363  	ts.Accumulate(schema.SpawnStruct("StructRepresentation_Stringjoin",
   364  		[]schema.StructField{
   365  			schema.SpawnStructField("join", "String", false, false),               // review: "delim" would seem more consistent with others -- but this is currently what the schema-schema says.
   366  			schema.SpawnStructField("fieldOrder", "List__FieldName", true, false), // todo: dodging inline defn's again.
   367  		},
   368  		schema.StructRepresentation_Map{},
   369  	))
   370  	ts.Accumulate(schema.SpawnStruct("StructRepresentation_Listpairs",
   371  		[]schema.StructField{},
   372  		schema.StructRepresentation_Map{},
   373  	))
   374  	ts.Accumulate(schema.SpawnStruct("TypeDefnEnum",
   375  		[]schema.StructField{
   376  			schema.SpawnStructField("members", "List__EnumMember", false, false),
   377  			schema.SpawnStructField("representation", "EnumRepresentation", false, false),
   378  		},
   379  		schema.StructRepresentation_Map{},
   380  	))
   381  	ts.Accumulate(schema.SpawnStruct("Unit", // todo: we should formalize the introdution of unit as first class type kind.
   382  		[]schema.StructField{},
   383  		schema.StructRepresentation_Map{},
   384  	))
   385  	ts.Accumulate(schema.SpawnList("List__EnumMember",
   386  		"EnumMember", false,
   387  	))
   388  	ts.Accumulate(schema.SpawnString("EnumMember"))
   389  	ts.Accumulate(schema.SpawnUnion("EnumRepresentation",
   390  		[]schema.TypeName{
   391  			"EnumRepresentation_String",
   392  			"EnumRepresentation_Int",
   393  		},
   394  		schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
   395  			"string": "EnumRepresentation_String",
   396  			"int":    "EnumRepresentation_Int",
   397  		}),
   398  	))
   399  	ts.Accumulate(schema.SpawnMap("EnumRepresentation_String",
   400  		"EnumMember", "String", false,
   401  	))
   402  	ts.Accumulate(schema.SpawnMap("EnumRepresentation_Int",
   403  		"EnumMember", "Int", false,
   404  	))
   405  	ts.Accumulate(schema.SpawnStruct("TypeDefnUnit",
   406  		[]schema.StructField{
   407  			schema.SpawnStructField("representation", "UnitRepresentation", false, false),
   408  		},
   409  		schema.StructRepresentation_Map{},
   410  	))
   411  	ts.Accumulate(schema.SpawnString("UnitRepresentation")) // TODO: enum
   412  	ts.Accumulate(schema.SpawnStruct("TypeDefnAny",
   413  		[]schema.StructField{},
   414  		schema.StructRepresentation_Map{},
   415  	))
   416  	ts.Accumulate(schema.SpawnStruct("TypeDefnCopy",
   417  		[]schema.StructField{
   418  			schema.SpawnStructField("fromType", "TypeName", false, false),
   419  		},
   420  		schema.StructRepresentation_Map{},
   421  	))
   422  	ts.Accumulate(schema.SpawnUnion("AnyScalar",
   423  		[]schema.TypeName{
   424  			"Bool",
   425  			"String",
   426  			"Bytes",
   427  			"Int",
   428  			"Float",
   429  		},
   430  		schema.SpawnUnionRepresentationKinded(map[datamodel.Kind]schema.TypeName{
   431  			datamodel.Kind_Bool:   "Bool",
   432  			datamodel.Kind_String: "String",
   433  			datamodel.Kind_Bytes:  "Bytes",
   434  			datamodel.Kind_Int:    "Int",
   435  			datamodel.Kind_Float:  "Float",
   436  		}),
   437  	))
   438  
   439  	if errs := ts.ValidateGraph(); errs != nil {
   440  		for _, err := range errs {
   441  			fmt.Printf("- %s\n", err)
   442  		}
   443  		panic("not happening")
   444  	}
   445  
   446  	TypeSystem = ts
   447  
   448  	Prototypes.Schema = bindnode.Prototype(
   449  		(*Schema)(nil),
   450  		TypeSystem.TypeByName("Schema"),
   451  	)
   452  }