package schemadmt import ( "fmt" "github.com/ipld/go-ipld-prime/datamodel" "github.com/ipld/go-ipld-prime/node/bindnode" "github.com/ipld/go-ipld-prime/schema" ) // Prototypes contains some schema.TypedPrototype values which match // the IPLD schema-schema -- that is, the schema that describes IPLD schemas. // These prototypes create an in-memory representation that is backed by // structs in this package and bindnode. var Prototypes struct { Schema schema.TypedPrototype } //go:generate go run -tags=schemadmtgen gen.go // TypeSystem is a compiled equivalent of the IPLD schema-schema -- that is, the schema that describes IPLD schemas. // // The IPLD schema-schema can be found at https://ipld.io/specs/schemas/schema-schema.ipldsch . var TypeSystem schema.TypeSystem // In this init function, we manually create a type system that *matches* the IPLD schema-schema. // This manual work is unfortunate, and also must be kept in-sync manually, // but is important because breaks a cyclic dependency -- // we use the compiled schema-schema produced by this to parse other schema documents. // We would also use it to parse... the IPLD schema-schema... if that weren't a cyclic dependency. func init() { var ts schema.TypeSystem ts.Init() // I've elided all references to Advancedlayouts stuff for the moment. // (Not because it's particularly hard or problematic; I just want to draw a slightly smaller circle first.) // Prelude ts.Accumulate(schema.SpawnString("String")) ts.Accumulate(schema.SpawnBool("Bool")) ts.Accumulate(schema.SpawnInt("Int")) ts.Accumulate(schema.SpawnFloat("Float")) ts.Accumulate(schema.SpawnBytes("Bytes")) // Schema-schema! // In the same order as the spec's ipldsch file. // Note that ADL stuff is excluded for now, as per above. ts.Accumulate(schema.SpawnString("TypeName")) ts.Accumulate(schema.SpawnStruct("Schema", []schema.StructField{ schema.SpawnStructField("types", "Map__TypeName__TypeDefn", false, false), // also: `advanced AdvancedDataLayoutMap`, but as commented above, we'll pursue this later. }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnMap("Map__TypeName__TypeDefn", "TypeName", "TypeDefn", false, )) ts.Accumulate(schema.SpawnUnion("TypeDefn", []schema.TypeName{ "TypeDefnBool", "TypeDefnString", "TypeDefnBytes", "TypeDefnInt", "TypeDefnFloat", "TypeDefnMap", "TypeDefnList", "TypeDefnLink", "TypeDefnUnion", "TypeDefnStruct", "TypeDefnEnum", "TypeDefnUnit", "TypeDefnAny", "TypeDefnCopy", }, // TODO: spec uses inline repr. schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{ "bool": "TypeDefnBool", "string": "TypeDefnString", "bytes": "TypeDefnBytes", "int": "TypeDefnInt", "float": "TypeDefnFloat", "map": "TypeDefnMap", "list": "TypeDefnList", "link": "TypeDefnLink", "union": "TypeDefnUnion", "struct": "TypeDefnStruct", "enum": "TypeDefnEnum", "unit": "TypeDefnUnit", "any": "TypeDefnAny", "copy": "TypeDefnCopy", }), )) ts.Accumulate(schema.SpawnUnion("TypeNameOrInlineDefn", []schema.TypeName{ "TypeName", "InlineDefn", }, schema.SpawnUnionRepresentationKinded(map[datamodel.Kind]schema.TypeName{ datamodel.Kind_String: "TypeName", datamodel.Kind_Map: "InlineDefn", }), )) ts.Accumulate(schema.SpawnUnion("InlineDefn", []schema.TypeName{ "TypeDefnMap", "TypeDefnList", "TypeDefnLink", }, schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{ "map": "TypeDefnMap", "list": "TypeDefnList", "link": "TypeDefnLink", }), )) ts.Accumulate(schema.SpawnStruct("TypeDefnBool", []schema.StructField{}, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("TypeDefnString", []schema.StructField{}, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("TypeDefnBytes", []schema.StructField{}, // No BytesRepresentation, since we omit ADL stuff. schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("TypeDefnInt", []schema.StructField{}, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("TypeDefnFloat", []schema.StructField{}, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("TypeDefnMap", []schema.StructField{ schema.SpawnStructField("keyType", "TypeName", false, false), schema.SpawnStructField("valueType", "TypeNameOrInlineDefn", false, false), schema.SpawnStructField("valueNullable", "Bool", true, false), // TODO: wants to use the "implicit" feature, but not supported yet schema.SpawnStructField("representation", "MapRepresentation", true, false), // XXXXXX }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnUnion("MapRepresentation", []schema.TypeName{ "MapRepresentation_Map", "MapRepresentation_Stringpairs", "MapRepresentation_Listpairs", }, schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{ "map": "MapRepresentation_Map", "stringpairs": "MapRepresentation_Stringpairs", "listpairs": "MapRepresentation_Listpairs", }), )) ts.Accumulate(schema.SpawnStruct("MapRepresentation_Map", []schema.StructField{}, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("MapRepresentation_Stringpairs", []schema.StructField{ schema.SpawnStructField("innerDelim", "String", false, false), schema.SpawnStructField("entryDelim", "String", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("MapRepresentation_Listpairs", []schema.StructField{}, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("TypeDefnList", []schema.StructField{ schema.SpawnStructField("valueType", "TypeNameOrInlineDefn", false, false), schema.SpawnStructField("valueNullable", "Bool", true, false), // TODO: wants to use the "implicit" feature, but not supported yet schema.SpawnStructField("representation", "ListRepresentation", true, false), // XXXXXX }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnUnion("ListRepresentation", []schema.TypeName{ "ListRepresentation_List", }, schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{ "list": "ListRepresentation_List", }), )) ts.Accumulate(schema.SpawnStruct("ListRepresentation_List", []schema.StructField{}, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("TypeDefnUnion", []schema.StructField{ // 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. schema.SpawnStructField("members", "List__UnionMember", false, false), schema.SpawnStructField("representation", "UnionRepresentation", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnList("List__UnionMember", "UnionMember", false, )) ts.Accumulate(schema.SpawnUnion("UnionMember", []schema.TypeName{ "TypeName", "UnionMemberInlineDefn", }, schema.SpawnUnionRepresentationKinded(map[datamodel.Kind]schema.TypeName{ datamodel.Kind_String: "TypeName", datamodel.Kind_Map: "UnionMemberInlineDefn", }), )) ts.Accumulate(schema.SpawnUnion("UnionMemberInlineDefn", []schema.TypeName{ "TypeDefnLink", }, schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{ "link": "TypeDefnLink", }), )) ts.Accumulate(schema.SpawnList("List__TypeName", // todo: this is a slight hack: should be an anon inside TypeDefnUnion.members. "TypeName", false, )) ts.Accumulate(schema.SpawnStruct("TypeDefnLink", []schema.StructField{ 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. }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnUnion("UnionRepresentation", []schema.TypeName{ "UnionRepresentation_Kinded", "UnionRepresentation_Keyed", "UnionRepresentation_Envelope", "UnionRepresentation_Inline", "UnionRepresentation_StringPrefix", "UnionRepresentation_BytesPrefix", }, schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{ "kinded": "UnionRepresentation_Kinded", "keyed": "UnionRepresentation_Keyed", "envelope": "UnionRepresentation_Envelope", "inline": "UnionRepresentation_Inline", "stringprefix": "UnionRepresentation_StringPrefix", "byteprefix": "UnionRepresentation_BytesPrefix", }), )) ts.Accumulate(schema.SpawnMap("UnionRepresentation_Kinded", "RepresentationKind", "UnionMember", false, )) ts.Accumulate(schema.SpawnMap("UnionRepresentation_Keyed", "String", "UnionMember", false, )) ts.Accumulate(schema.SpawnMap("Map__String__UnionMember", "TypeName", "TypeDefn", false, )) ts.Accumulate(schema.SpawnStruct("UnionRepresentation_Envelope", []schema.StructField{ schema.SpawnStructField("discriminantKey", "String", false, false), schema.SpawnStructField("contentKey", "String", false, false), schema.SpawnStructField("discriminantTable", "Map__String__UnionMember", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("UnionRepresentation_Inline", []schema.StructField{ schema.SpawnStructField("discriminantKey", "String", false, false), schema.SpawnStructField("discriminantTable", "Map__String__TypeName", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("UnionRepresentation_StringPrefix", []schema.StructField{ schema.SpawnStructField("prefixes", "Map__String__TypeName", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("UnionRepresentation_BytesPrefix", []schema.StructField{ schema.SpawnStructField("prefixes", "Map__HexString__TypeName", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnMap("Map__HexString__TypeName", "String", "TypeName", false, )) ts.Accumulate(schema.SpawnString("HexString")) ts.Accumulate(schema.SpawnMap("Map__String__TypeName", "String", "TypeName", false, )) ts.Accumulate(schema.SpawnMap("Map__TypeName__Int", "String", "Int", false, )) ts.Accumulate(schema.SpawnString("RepresentationKind")) // todo: RepresentationKind is supposed to be an enum, but we're puting it to a string atm. ts.Accumulate(schema.SpawnStruct("TypeDefnStruct", []schema.StructField{ schema.SpawnStructField("fields", "Map__FieldName__StructField", false, false), // todo: dodging inline defn's again. schema.SpawnStructField("representation", "StructRepresentation", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnMap("Map__FieldName__StructField", "FieldName", "StructField", false, )) ts.Accumulate(schema.SpawnString("FieldName")) ts.Accumulate(schema.SpawnStruct("StructField", []schema.StructField{ schema.SpawnStructField("type", "TypeNameOrInlineDefn", false, false), schema.SpawnStructField("optional", "Bool", true, false), // todo: wants to use the "implicit" feature, but not supported yet schema.SpawnStructField("nullable", "Bool", true, false), // todo: wants to use the "implicit" feature, but not supported yet }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnUnion("StructRepresentation", []schema.TypeName{ "StructRepresentation_Map", "StructRepresentation_Tuple", "StructRepresentation_Stringpairs", "StructRepresentation_Stringjoin", "StructRepresentation_Listpairs", }, schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{ "map": "StructRepresentation_Map", "tuple": "StructRepresentation_Tuple", "stringpairs": "StructRepresentation_Stringpairs", "stringjoin": "StructRepresentation_Stringjoin", "listpairs": "StructRepresentation_Listpairs", }), )) ts.Accumulate(schema.SpawnStruct("StructRepresentation_Map", []schema.StructField{ schema.SpawnStructField("fields", "Map__FieldName__StructRepresentation_Map_FieldDetails", true, false), // todo: dodging inline defn's again. }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnMap("Map__FieldName__StructRepresentation_Map_FieldDetails", "FieldName", "StructRepresentation_Map_FieldDetails", false, )) ts.Accumulate(schema.SpawnStruct("StructRepresentation_Map_FieldDetails", []schema.StructField{ schema.SpawnStructField("rename", "String", true, false), schema.SpawnStructField("implicit", "AnyScalar", true, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("StructRepresentation_Tuple", []schema.StructField{ schema.SpawnStructField("fieldOrder", "List__FieldName", true, false), // todo: dodging inline defn's again. }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnList("List__FieldName", "FieldName", false, )) ts.Accumulate(schema.SpawnStruct("StructRepresentation_Stringpairs", []schema.StructField{ schema.SpawnStructField("innerDelim", "String", false, false), schema.SpawnStructField("entryDelim", "String", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("StructRepresentation_Stringjoin", []schema.StructField{ schema.SpawnStructField("join", "String", false, false), // review: "delim" would seem more consistent with others -- but this is currently what the schema-schema says. schema.SpawnStructField("fieldOrder", "List__FieldName", true, false), // todo: dodging inline defn's again. }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("StructRepresentation_Listpairs", []schema.StructField{}, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("TypeDefnEnum", []schema.StructField{ schema.SpawnStructField("members", "List__EnumMember", false, false), schema.SpawnStructField("representation", "EnumRepresentation", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("Unit", // todo: we should formalize the introdution of unit as first class type kind. []schema.StructField{}, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnList("List__EnumMember", "EnumMember", false, )) ts.Accumulate(schema.SpawnString("EnumMember")) ts.Accumulate(schema.SpawnUnion("EnumRepresentation", []schema.TypeName{ "EnumRepresentation_String", "EnumRepresentation_Int", }, schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{ "string": "EnumRepresentation_String", "int": "EnumRepresentation_Int", }), )) ts.Accumulate(schema.SpawnMap("EnumRepresentation_String", "EnumMember", "String", false, )) ts.Accumulate(schema.SpawnMap("EnumRepresentation_Int", "EnumMember", "Int", false, )) ts.Accumulate(schema.SpawnStruct("TypeDefnUnit", []schema.StructField{ schema.SpawnStructField("representation", "UnitRepresentation", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnString("UnitRepresentation")) // TODO: enum ts.Accumulate(schema.SpawnStruct("TypeDefnAny", []schema.StructField{}, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnStruct("TypeDefnCopy", []schema.StructField{ schema.SpawnStructField("fromType", "TypeName", false, false), }, schema.StructRepresentation_Map{}, )) ts.Accumulate(schema.SpawnUnion("AnyScalar", []schema.TypeName{ "Bool", "String", "Bytes", "Int", "Float", }, schema.SpawnUnionRepresentationKinded(map[datamodel.Kind]schema.TypeName{ datamodel.Kind_Bool: "Bool", datamodel.Kind_String: "String", datamodel.Kind_Bytes: "Bytes", datamodel.Kind_Int: "Int", datamodel.Kind_Float: "Float", }), )) if errs := ts.ValidateGraph(); errs != nil { for _, err := range errs { fmt.Printf("- %s\n", err) } panic("not happening") } TypeSystem = ts Prototypes.Schema = bindnode.Prototype( (*Schema)(nil), TypeSystem.TypeByName("Schema"), ) }