Integrate BACKBEAT SDK and resolve KACHING license validation
Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
427
vendor/github.com/ipld/go-ipld-prime/schema/dmt/compile.go
generated
vendored
Normal file
427
vendor/github.com/ipld/go-ipld-prime/schema/dmt/compile.go
generated
vendored
Normal file
@@ -0,0 +1,427 @@
|
||||
package schemadmt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
"github.com/ipld/go-ipld-prime/schema"
|
||||
)
|
||||
|
||||
// Compile transforms a description of a schema in raw data model ("dmt") form
|
||||
// into a compiled schema.TypeSystem, which is the ready-to-use form.
|
||||
//
|
||||
// The first parameter is mutated by this process,
|
||||
// and the second parameter is the data source.
|
||||
//
|
||||
// The compilation process includes first inserting the "prelude" types into the
|
||||
// schema.TypeSystem -- that is, the "type Bool bool" and "type String string", etc,
|
||||
// which are generally presumed to be present in any type system.
|
||||
//
|
||||
// The compilation process attempts to check the validity of the schema at a logical level as it goes.
|
||||
// For example, references to type names not present elsewhere in the same schema are now an error
|
||||
// (even though that has been easily representable in the dmt.Schema form up until this point).
|
||||
//
|
||||
// Note that this API is EXPERIMENTAL and will likely change.
|
||||
// It supports many features of IPLD Schemas,
|
||||
// but it may yet not support all of them.
|
||||
// It supports several validations for logical coherency of schemas,
|
||||
// but may not yet successfully reject all invalid schemas.
|
||||
func Compile(ts *schema.TypeSystem, node *Schema) error {
|
||||
// Prelude; probably belongs elsewhere.
|
||||
{
|
||||
ts.Accumulate(schema.SpawnBool("Bool"))
|
||||
ts.Accumulate(schema.SpawnInt("Int"))
|
||||
ts.Accumulate(schema.SpawnFloat("Float"))
|
||||
ts.Accumulate(schema.SpawnString("String"))
|
||||
ts.Accumulate(schema.SpawnBytes("Bytes"))
|
||||
|
||||
ts.Accumulate(schema.SpawnAny("Any"))
|
||||
|
||||
ts.Accumulate(schema.SpawnMap("Map", "String", "Any", false))
|
||||
ts.Accumulate(schema.SpawnList("List", "Any", false))
|
||||
|
||||
// Should be &Any, really.
|
||||
ts.Accumulate(schema.SpawnLink("Link"))
|
||||
|
||||
// TODO: schema package lacks support?
|
||||
// ts.Accumulate(schema.SpawnUnit("Null", NullRepr))
|
||||
}
|
||||
|
||||
for _, name := range node.Types.Keys {
|
||||
defn := node.Types.Values[name]
|
||||
|
||||
// TODO: once ./schema supports anonymous/inline types, remove the ts argument.
|
||||
typ, err := spawnType(ts, name, defn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ts.Accumulate(typ)
|
||||
}
|
||||
|
||||
// TODO: if this fails and the user forgot to check Compile's returned error,
|
||||
// we can leave the TypeSystem in an unfortunate broken state:
|
||||
// they can obtain types out of the TypeSystem and they are non-nil,
|
||||
// but trying to use them in any way may result in panics.
|
||||
// Consider making that less prone to misuse, such as making it illegal to
|
||||
// call TypeByName until ValidateGraph is happy.
|
||||
if errs := ts.ValidateGraph(); errs != nil {
|
||||
// Return the first error.
|
||||
for _, err := range errs {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Note that the parser and compiler support defaults. We're lacking support in bindnode.
|
||||
func todoFromImplicitlyFalseBool(b *bool) bool {
|
||||
if b == nil {
|
||||
return false
|
||||
}
|
||||
return *b
|
||||
}
|
||||
|
||||
func anonTypeName(nameOrDefn TypeNameOrInlineDefn) string {
|
||||
if nameOrDefn.TypeName != nil {
|
||||
return *nameOrDefn.TypeName
|
||||
}
|
||||
defn := *nameOrDefn.InlineDefn
|
||||
switch {
|
||||
case defn.TypeDefnMap != nil:
|
||||
defn := defn.TypeDefnMap
|
||||
return fmt.Sprintf("Map__%s__%s", defn.KeyType, anonTypeName(defn.ValueType))
|
||||
case defn.TypeDefnList != nil:
|
||||
defn := defn.TypeDefnList
|
||||
return fmt.Sprintf("List__%s", anonTypeName(defn.ValueType))
|
||||
case defn.TypeDefnLink != nil:
|
||||
return anonLinkName(*defn.TypeDefnLink)
|
||||
default:
|
||||
panic(fmt.Errorf("%#v", defn))
|
||||
}
|
||||
}
|
||||
|
||||
func anonLinkName(defn TypeDefnLink) string {
|
||||
if defn.ExpectedType != nil {
|
||||
return fmt.Sprintf("Link__%s", *defn.ExpectedType)
|
||||
}
|
||||
return "Link__Link"
|
||||
}
|
||||
|
||||
func parseKind(s string) datamodel.Kind {
|
||||
switch s {
|
||||
case "map":
|
||||
return datamodel.Kind_Map
|
||||
case "list":
|
||||
return datamodel.Kind_List
|
||||
case "null":
|
||||
return datamodel.Kind_Null
|
||||
case "bool":
|
||||
return datamodel.Kind_Bool
|
||||
case "int":
|
||||
return datamodel.Kind_Int
|
||||
case "float":
|
||||
return datamodel.Kind_Float
|
||||
case "string":
|
||||
return datamodel.Kind_String
|
||||
case "bytes":
|
||||
return datamodel.Kind_Bytes
|
||||
case "link":
|
||||
return datamodel.Kind_Link
|
||||
default:
|
||||
return datamodel.Kind_Invalid
|
||||
}
|
||||
}
|
||||
|
||||
func spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (schema.Type, error) {
|
||||
switch {
|
||||
// Scalar types without parameters.
|
||||
case defn.TypeDefnBool != nil:
|
||||
return schema.SpawnBool(name), nil
|
||||
case defn.TypeDefnString != nil:
|
||||
return schema.SpawnString(name), nil
|
||||
case defn.TypeDefnBytes != nil:
|
||||
return schema.SpawnBytes(name), nil
|
||||
case defn.TypeDefnInt != nil:
|
||||
return schema.SpawnInt(name), nil
|
||||
case defn.TypeDefnFloat != nil:
|
||||
return schema.SpawnFloat(name), nil
|
||||
|
||||
case defn.TypeDefnList != nil:
|
||||
typ := defn.TypeDefnList
|
||||
tname := ""
|
||||
if typ.ValueType.TypeName != nil {
|
||||
tname = *typ.ValueType.TypeName
|
||||
} else if tname = anonTypeName(typ.ValueType); ts.TypeByName(tname) == nil {
|
||||
anonDefn := TypeDefn{
|
||||
TypeDefnMap: typ.ValueType.InlineDefn.TypeDefnMap,
|
||||
TypeDefnList: typ.ValueType.InlineDefn.TypeDefnList,
|
||||
TypeDefnLink: typ.ValueType.InlineDefn.TypeDefnLink,
|
||||
}
|
||||
anonType, err := spawnType(ts, tname, anonDefn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts.Accumulate(anonType)
|
||||
}
|
||||
switch {
|
||||
case typ.Representation == nil ||
|
||||
typ.Representation.ListRepresentation_List != nil:
|
||||
// default behavior
|
||||
default:
|
||||
return nil, fmt.Errorf("TODO: support other list repr in schema package")
|
||||
}
|
||||
return schema.SpawnList(name,
|
||||
tname,
|
||||
todoFromImplicitlyFalseBool(typ.ValueNullable),
|
||||
), nil
|
||||
case defn.TypeDefnMap != nil:
|
||||
typ := defn.TypeDefnMap
|
||||
tname := ""
|
||||
if typ.ValueType.TypeName != nil {
|
||||
tname = *typ.ValueType.TypeName
|
||||
} else if tname = anonTypeName(typ.ValueType); ts.TypeByName(tname) == nil {
|
||||
anonDefn := TypeDefn{
|
||||
TypeDefnMap: typ.ValueType.InlineDefn.TypeDefnMap,
|
||||
TypeDefnList: typ.ValueType.InlineDefn.TypeDefnList,
|
||||
TypeDefnLink: typ.ValueType.InlineDefn.TypeDefnLink,
|
||||
}
|
||||
anonType, err := spawnType(ts, tname, anonDefn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts.Accumulate(anonType)
|
||||
}
|
||||
switch {
|
||||
case typ.Representation == nil ||
|
||||
typ.Representation.MapRepresentation_Map != nil:
|
||||
// default behavior
|
||||
case typ.Representation.MapRepresentation_Stringpairs != nil:
|
||||
return nil, fmt.Errorf("TODO: support stringpairs map repr in schema package")
|
||||
default:
|
||||
return nil, fmt.Errorf("TODO: support other map repr in schema package")
|
||||
}
|
||||
return schema.SpawnMap(name,
|
||||
typ.KeyType,
|
||||
tname,
|
||||
todoFromImplicitlyFalseBool(typ.ValueNullable),
|
||||
), nil
|
||||
case defn.TypeDefnStruct != nil:
|
||||
typ := defn.TypeDefnStruct
|
||||
var fields []schema.StructField
|
||||
for _, fname := range typ.Fields.Keys {
|
||||
field := typ.Fields.Values[fname]
|
||||
tname := ""
|
||||
if field.Type.TypeName != nil {
|
||||
tname = *field.Type.TypeName
|
||||
} else if tname = anonTypeName(field.Type); ts.TypeByName(tname) == nil {
|
||||
// Note that TypeDefn and InlineDefn aren't the same enum.
|
||||
anonDefn := TypeDefn{
|
||||
TypeDefnMap: field.Type.InlineDefn.TypeDefnMap,
|
||||
TypeDefnList: field.Type.InlineDefn.TypeDefnList,
|
||||
TypeDefnLink: field.Type.InlineDefn.TypeDefnLink,
|
||||
}
|
||||
anonType, err := spawnType(ts, tname, anonDefn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts.Accumulate(anonType)
|
||||
}
|
||||
fields = append(fields, schema.SpawnStructField(fname,
|
||||
tname,
|
||||
todoFromImplicitlyFalseBool(field.Optional),
|
||||
todoFromImplicitlyFalseBool(field.Nullable),
|
||||
))
|
||||
}
|
||||
var repr schema.StructRepresentation
|
||||
switch {
|
||||
case typ.Representation.StructRepresentation_Map != nil:
|
||||
rp := typ.Representation.StructRepresentation_Map
|
||||
if rp.Fields == nil {
|
||||
repr = schema.SpawnStructRepresentationMap2(nil, nil)
|
||||
break
|
||||
}
|
||||
renames := make(map[string]string, len(rp.Fields.Keys))
|
||||
implicits := make(map[string]schema.ImplicitValue, len(rp.Fields.Keys))
|
||||
for _, name := range rp.Fields.Keys {
|
||||
details := rp.Fields.Values[name]
|
||||
if details.Rename != nil {
|
||||
renames[name] = *details.Rename
|
||||
}
|
||||
if imp := details.Implicit; imp != nil {
|
||||
var sumVal schema.ImplicitValue
|
||||
switch {
|
||||
case imp.Bool != nil:
|
||||
sumVal = schema.ImplicitValue_Bool(*imp.Bool)
|
||||
case imp.String != nil:
|
||||
sumVal = schema.ImplicitValue_String(*imp.String)
|
||||
case imp.Int != nil:
|
||||
sumVal = schema.ImplicitValue_Int(*imp.Int)
|
||||
default:
|
||||
panic("TODO: implicit value kind")
|
||||
}
|
||||
implicits[name] = sumVal
|
||||
}
|
||||
|
||||
}
|
||||
repr = schema.SpawnStructRepresentationMap2(renames, implicits)
|
||||
case typ.Representation.StructRepresentation_Tuple != nil:
|
||||
rp := typ.Representation.StructRepresentation_Tuple
|
||||
if rp.FieldOrder == nil {
|
||||
repr = schema.SpawnStructRepresentationTuple()
|
||||
break
|
||||
}
|
||||
return nil, fmt.Errorf("TODO: support for tuples with field orders in the schema package")
|
||||
case typ.Representation.StructRepresentation_Stringjoin != nil:
|
||||
join := typ.Representation.StructRepresentation_Stringjoin.Join
|
||||
if join == "" {
|
||||
return nil, fmt.Errorf("stringjoin has empty join value")
|
||||
}
|
||||
repr = schema.SpawnStructRepresentationStringjoin(join)
|
||||
default:
|
||||
return nil, fmt.Errorf("TODO: support other struct repr in schema package")
|
||||
}
|
||||
return schema.SpawnStruct(name,
|
||||
fields,
|
||||
repr,
|
||||
), nil
|
||||
case defn.TypeDefnUnion != nil:
|
||||
typ := defn.TypeDefnUnion
|
||||
var members []schema.TypeName
|
||||
for _, member := range typ.Members {
|
||||
if member.TypeName != nil {
|
||||
members = append(members, *member.TypeName)
|
||||
} else {
|
||||
tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)
|
||||
members = append(members, tname)
|
||||
if ts.TypeByName(tname) == nil {
|
||||
anonDefn := TypeDefn{
|
||||
TypeDefnLink: member.UnionMemberInlineDefn.TypeDefnLink,
|
||||
}
|
||||
anonType, err := spawnType(ts, tname, anonDefn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts.Accumulate(anonType)
|
||||
}
|
||||
}
|
||||
}
|
||||
remainingMembers := make(map[string]bool)
|
||||
for _, memberName := range members {
|
||||
remainingMembers[memberName] = true
|
||||
}
|
||||
validMember := func(memberName string) error {
|
||||
switch remaining, known := remainingMembers[memberName]; {
|
||||
case remaining:
|
||||
remainingMembers[memberName] = false
|
||||
return nil
|
||||
case !known:
|
||||
return fmt.Errorf("%q is not a valid member of union %q", memberName, name)
|
||||
default:
|
||||
return fmt.Errorf("%q is duplicate in the union repr of %q", memberName, name)
|
||||
}
|
||||
}
|
||||
|
||||
var repr schema.UnionRepresentation
|
||||
switch {
|
||||
case typ.Representation.UnionRepresentation_Kinded != nil:
|
||||
rp := typ.Representation.UnionRepresentation_Kinded
|
||||
table := make(map[datamodel.Kind]schema.TypeName, len(rp.Keys))
|
||||
for _, kindStr := range rp.Keys {
|
||||
kind := parseKind(kindStr)
|
||||
member := rp.Values[kindStr]
|
||||
switch {
|
||||
case member.TypeName != nil:
|
||||
memberName := *member.TypeName
|
||||
validMember(memberName)
|
||||
table[kind] = memberName
|
||||
case member.UnionMemberInlineDefn != nil:
|
||||
tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)
|
||||
validMember(tname)
|
||||
table[kind] = tname
|
||||
}
|
||||
}
|
||||
repr = schema.SpawnUnionRepresentationKinded(table)
|
||||
case typ.Representation.UnionRepresentation_Keyed != nil:
|
||||
rp := typ.Representation.UnionRepresentation_Keyed
|
||||
table := make(map[string]schema.TypeName, len(rp.Keys))
|
||||
for _, key := range rp.Keys {
|
||||
member := rp.Values[key]
|
||||
switch {
|
||||
case member.TypeName != nil:
|
||||
memberName := *member.TypeName
|
||||
validMember(memberName)
|
||||
table[key] = memberName
|
||||
case member.UnionMemberInlineDefn != nil:
|
||||
tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)
|
||||
validMember(tname)
|
||||
table[key] = tname
|
||||
}
|
||||
}
|
||||
repr = schema.SpawnUnionRepresentationKeyed(table)
|
||||
case typ.Representation.UnionRepresentation_StringPrefix != nil:
|
||||
prefixes := typ.Representation.UnionRepresentation_StringPrefix.Prefixes
|
||||
for _, key := range prefixes.Keys {
|
||||
validMember(prefixes.Values[key])
|
||||
}
|
||||
repr = schema.SpawnUnionRepresentationStringprefix("", prefixes.Values)
|
||||
default:
|
||||
return nil, fmt.Errorf("TODO: support other union repr in schema package")
|
||||
}
|
||||
for memberName, remaining := range remainingMembers {
|
||||
if remaining {
|
||||
return nil, fmt.Errorf("%q is not present in the union repr of %q", memberName, name)
|
||||
}
|
||||
}
|
||||
return schema.SpawnUnion(name,
|
||||
members,
|
||||
repr,
|
||||
), nil
|
||||
case defn.TypeDefnEnum != nil:
|
||||
typ := defn.TypeDefnEnum
|
||||
var repr schema.EnumRepresentation
|
||||
|
||||
// TODO: we should probably also reject duplicates.
|
||||
validMember := func(name string) bool {
|
||||
for _, memberName := range typ.Members {
|
||||
if memberName == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
switch {
|
||||
case typ.Representation.EnumRepresentation_String != nil:
|
||||
rp := typ.Representation.EnumRepresentation_String
|
||||
for memberName := range rp.Values {
|
||||
if !validMember(memberName) {
|
||||
return nil, fmt.Errorf("%q is not a valid member of enum %q", memberName, name)
|
||||
}
|
||||
}
|
||||
repr = schema.EnumRepresentation_String(rp.Values)
|
||||
case typ.Representation.EnumRepresentation_Int != nil:
|
||||
rp := typ.Representation.EnumRepresentation_Int
|
||||
for memberName := range rp.Values {
|
||||
if !validMember(memberName) {
|
||||
return nil, fmt.Errorf("%q is not a valid member of enum %q", memberName, name)
|
||||
}
|
||||
}
|
||||
repr = schema.EnumRepresentation_Int(rp.Values)
|
||||
default:
|
||||
return nil, fmt.Errorf("TODO: support other enum repr in schema package")
|
||||
}
|
||||
return schema.SpawnEnum(name,
|
||||
typ.Members,
|
||||
repr,
|
||||
), nil
|
||||
case defn.TypeDefnLink != nil:
|
||||
typ := defn.TypeDefnLink
|
||||
if typ.ExpectedType == nil {
|
||||
return schema.SpawnLink(name), nil
|
||||
}
|
||||
return schema.SpawnLinkReference(name, *typ.ExpectedType), nil
|
||||
case defn.TypeDefnAny != nil:
|
||||
return schema.SpawnAny(name), nil
|
||||
default:
|
||||
panic(fmt.Errorf("%#v", defn))
|
||||
}
|
||||
}
|
||||
30
vendor/github.com/ipld/go-ipld-prime/schema/dmt/doc.go
generated
vendored
Normal file
30
vendor/github.com/ipld/go-ipld-prime/schema/dmt/doc.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Package schema/dmt contains types and functions for dealing with the data model form of IPLD Schemas.
|
||||
|
||||
(DMT is short for "data model tree" -- see https://ipld.io/glossary/#dmt .)
|
||||
|
||||
As with anything that's IPLD data model, this data can be serialized or deserialized into a wide variety of codecs.
|
||||
|
||||
To contrast this package with some of its neighbors and with some various formats for the data this package describes:
|
||||
Schemas also have a DSL (a domain-specific language -- something that's meant to look nice, and be easy for humans to read and write),
|
||||
which are parsed by the `schema/dsl` package, and produce a DMT form (defined by and handled by this package).
|
||||
Schemas also have a compiled form, which is the in-memory structure that this library uses when working with them;
|
||||
this compiled form differs from the DMT because it can use pointers (and that includes cyclic pointers, which is something the DMT form cannot contain).
|
||||
We use the DMT form (this package) to produce the compiled form (which is the `schema` package).
|
||||
|
||||
Creating a Compiled schema either flows from DSL(text)->`schema/dsl`->`schema/dmt`->`schema`,
|
||||
or just (some codec, e.g. JSON or CBOR or etc)->`schema/dmt`->`schema`.
|
||||
|
||||
The `dmt.Schema` type describes the data found at the root of an IPLD Schema document.
|
||||
The `Compile` function turns such data into a `schema.TypeSystem` that is ready to be used.
|
||||
The `dmt.Prototype.Schema` value is a NodePrototype that can be used to handle IPLD Schemas in DMT form as regular IPLD Nodes.
|
||||
|
||||
Typically this package is imported aliased as "schemadmt",
|
||||
since "dmt" is a fairly generic term in the IPLD ecosystem
|
||||
(see https://ipld.io/glossary/#dmt ).
|
||||
|
||||
Many types in this package lack documentation directly on the type;
|
||||
generally, these are structs that match the IPLD schema-schema,
|
||||
and so you can find descriptions of them in documentation for the schema-schema.
|
||||
*/
|
||||
package schemadmt
|
||||
27
vendor/github.com/ipld/go-ipld-prime/schema/dmt/operations.go
generated
vendored
Normal file
27
vendor/github.com/ipld/go-ipld-prime/schema/dmt/operations.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package schemadmt
|
||||
|
||||
import (
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
"github.com/ipld/go-ipld-prime/node/bindnode"
|
||||
)
|
||||
|
||||
// ConcatenateSchemas returns a new schema DMT object containing the
|
||||
// type declarations from both.
|
||||
//
|
||||
// As is usual for DMT form data, there is no check about the validity
|
||||
// of the result yet; you'll need to apply `Compile` on the produced value
|
||||
// to produce a usable compiled typesystem or to become certain that
|
||||
// all references in the DMT are satisfied, etc.
|
||||
func ConcatenateSchemas(a, b *Schema) *Schema {
|
||||
// The joy of having an intermediate form that's just regular data model:
|
||||
// we can implement this by simply using data model "copy" operations,
|
||||
// and the result is correct.
|
||||
nb := Prototypes.Schema.NewBuilder()
|
||||
if err := datamodel.Copy(bindnode.Wrap(a, Prototypes.Schema.Type()), nb); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := datamodel.Copy(bindnode.Wrap(b, Prototypes.Schema.Type()), nb); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bindnode.Unwrap(nb.Build()).(*Schema)
|
||||
}
|
||||
452
vendor/github.com/ipld/go-ipld-prime/schema/dmt/schema.go
generated
vendored
Normal file
452
vendor/github.com/ipld/go-ipld-prime/schema/dmt/schema.go
generated
vendored
Normal file
@@ -0,0 +1,452 @@
|
||||
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"),
|
||||
)
|
||||
}
|
||||
215
vendor/github.com/ipld/go-ipld-prime/schema/dmt/types.go
generated
vendored
Normal file
215
vendor/github.com/ipld/go-ipld-prime/schema/dmt/types.go
generated
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
package schemadmt
|
||||
|
||||
type Schema struct {
|
||||
Types Map__TypeName__TypeDefn
|
||||
}
|
||||
type Map__TypeName__TypeDefn struct {
|
||||
Keys []string
|
||||
Values map[string]TypeDefn
|
||||
}
|
||||
type TypeDefn struct {
|
||||
TypeDefnBool *TypeDefnBool
|
||||
TypeDefnString *TypeDefnString
|
||||
TypeDefnBytes *TypeDefnBytes
|
||||
TypeDefnInt *TypeDefnInt
|
||||
TypeDefnFloat *TypeDefnFloat
|
||||
TypeDefnMap *TypeDefnMap
|
||||
TypeDefnList *TypeDefnList
|
||||
TypeDefnLink *TypeDefnLink
|
||||
TypeDefnUnion *TypeDefnUnion
|
||||
TypeDefnStruct *TypeDefnStruct
|
||||
TypeDefnEnum *TypeDefnEnum
|
||||
TypeDefnUnit *TypeDefnUnit
|
||||
TypeDefnAny *TypeDefnAny
|
||||
TypeDefnCopy *TypeDefnCopy
|
||||
}
|
||||
type TypeNameOrInlineDefn struct {
|
||||
TypeName *string
|
||||
InlineDefn *InlineDefn
|
||||
}
|
||||
type InlineDefn struct {
|
||||
TypeDefnMap *TypeDefnMap
|
||||
TypeDefnList *TypeDefnList
|
||||
TypeDefnLink *TypeDefnLink
|
||||
}
|
||||
type TypeDefnBool struct {
|
||||
}
|
||||
type TypeDefnString struct {
|
||||
}
|
||||
type TypeDefnBytes struct {
|
||||
}
|
||||
type TypeDefnInt struct {
|
||||
}
|
||||
type TypeDefnFloat struct {
|
||||
}
|
||||
type TypeDefnMap struct {
|
||||
KeyType string
|
||||
ValueType TypeNameOrInlineDefn
|
||||
ValueNullable *bool
|
||||
Representation *MapRepresentation
|
||||
}
|
||||
type MapRepresentation struct {
|
||||
MapRepresentation_Map *MapRepresentation_Map
|
||||
MapRepresentation_Stringpairs *MapRepresentation_Stringpairs
|
||||
MapRepresentation_Listpairs *MapRepresentation_Listpairs
|
||||
}
|
||||
type MapRepresentation_Map struct {
|
||||
}
|
||||
type MapRepresentation_Stringpairs struct {
|
||||
InnerDelim string
|
||||
EntryDelim string
|
||||
}
|
||||
type MapRepresentation_Listpairs struct {
|
||||
}
|
||||
type TypeDefnList struct {
|
||||
ValueType TypeNameOrInlineDefn
|
||||
ValueNullable *bool
|
||||
Representation *ListRepresentation
|
||||
}
|
||||
type ListRepresentation struct {
|
||||
ListRepresentation_List *ListRepresentation_List
|
||||
}
|
||||
type ListRepresentation_List struct {
|
||||
}
|
||||
type TypeDefnUnion struct {
|
||||
Members List__UnionMember
|
||||
Representation UnionRepresentation
|
||||
}
|
||||
type List__UnionMember []UnionMember
|
||||
type UnionMember struct {
|
||||
TypeName *string
|
||||
UnionMemberInlineDefn *UnionMemberInlineDefn
|
||||
}
|
||||
type UnionMemberInlineDefn struct {
|
||||
TypeDefnLink *TypeDefnLink
|
||||
}
|
||||
type List__TypeName []string
|
||||
type TypeDefnLink struct {
|
||||
ExpectedType *string
|
||||
}
|
||||
type UnionRepresentation struct {
|
||||
UnionRepresentation_Kinded *UnionRepresentation_Kinded
|
||||
UnionRepresentation_Keyed *UnionRepresentation_Keyed
|
||||
UnionRepresentation_Envelope *UnionRepresentation_Envelope
|
||||
UnionRepresentation_Inline *UnionRepresentation_Inline
|
||||
UnionRepresentation_StringPrefix *UnionRepresentation_StringPrefix
|
||||
UnionRepresentation_BytesPrefix *UnionRepresentation_BytesPrefix
|
||||
}
|
||||
type UnionRepresentation_Kinded struct {
|
||||
Keys []string
|
||||
Values map[string]UnionMember
|
||||
}
|
||||
type UnionRepresentation_Keyed struct {
|
||||
Keys []string
|
||||
Values map[string]UnionMember
|
||||
}
|
||||
type Map__String__UnionMember struct {
|
||||
Keys []string
|
||||
Values map[string]TypeDefn
|
||||
}
|
||||
type UnionRepresentation_Envelope struct {
|
||||
DiscriminantKey string
|
||||
ContentKey string
|
||||
DiscriminantTable Map__String__UnionMember
|
||||
}
|
||||
type UnionRepresentation_Inline struct {
|
||||
DiscriminantKey string
|
||||
DiscriminantTable Map__String__TypeName
|
||||
}
|
||||
type UnionRepresentation_StringPrefix struct {
|
||||
Prefixes Map__String__TypeName
|
||||
}
|
||||
type UnionRepresentation_BytesPrefix struct {
|
||||
Prefixes Map__HexString__TypeName
|
||||
}
|
||||
type Map__HexString__TypeName struct {
|
||||
Keys []string
|
||||
Values map[string]string
|
||||
}
|
||||
type Map__String__TypeName struct {
|
||||
Keys []string
|
||||
Values map[string]string
|
||||
}
|
||||
type Map__TypeName__Int struct {
|
||||
Keys []string
|
||||
Values map[string]int
|
||||
}
|
||||
type TypeDefnStruct struct {
|
||||
Fields Map__FieldName__StructField
|
||||
Representation StructRepresentation
|
||||
}
|
||||
type Map__FieldName__StructField struct {
|
||||
Keys []string
|
||||
Values map[string]StructField
|
||||
}
|
||||
type StructField struct {
|
||||
Type TypeNameOrInlineDefn
|
||||
Optional *bool
|
||||
Nullable *bool
|
||||
}
|
||||
type StructRepresentation struct {
|
||||
StructRepresentation_Map *StructRepresentation_Map
|
||||
StructRepresentation_Tuple *StructRepresentation_Tuple
|
||||
StructRepresentation_Stringpairs *StructRepresentation_Stringpairs
|
||||
StructRepresentation_Stringjoin *StructRepresentation_Stringjoin
|
||||
StructRepresentation_Listpairs *StructRepresentation_Listpairs
|
||||
}
|
||||
type StructRepresentation_Map struct {
|
||||
Fields *Map__FieldName__StructRepresentation_Map_FieldDetails
|
||||
}
|
||||
type Map__FieldName__StructRepresentation_Map_FieldDetails struct {
|
||||
Keys []string
|
||||
Values map[string]StructRepresentation_Map_FieldDetails
|
||||
}
|
||||
type StructRepresentation_Map_FieldDetails struct {
|
||||
Rename *string
|
||||
Implicit *AnyScalar
|
||||
}
|
||||
type StructRepresentation_Tuple struct {
|
||||
FieldOrder *List__FieldName
|
||||
}
|
||||
type List__FieldName []string
|
||||
type StructRepresentation_Stringpairs struct {
|
||||
InnerDelim string
|
||||
EntryDelim string
|
||||
}
|
||||
type StructRepresentation_Stringjoin struct {
|
||||
Join string
|
||||
FieldOrder *List__FieldName
|
||||
}
|
||||
type StructRepresentation_Listpairs struct {
|
||||
}
|
||||
type TypeDefnEnum struct {
|
||||
Members List__EnumMember
|
||||
Representation EnumRepresentation
|
||||
}
|
||||
type Unit struct {
|
||||
}
|
||||
type List__EnumMember []string
|
||||
type EnumRepresentation struct {
|
||||
EnumRepresentation_String *EnumRepresentation_String
|
||||
EnumRepresentation_Int *EnumRepresentation_Int
|
||||
}
|
||||
type EnumRepresentation_String struct {
|
||||
Keys []string
|
||||
Values map[string]string
|
||||
}
|
||||
type EnumRepresentation_Int struct {
|
||||
Keys []string
|
||||
Values map[string]int
|
||||
}
|
||||
type TypeDefnUnit struct {
|
||||
Representation string
|
||||
}
|
||||
type TypeDefnAny struct {
|
||||
}
|
||||
type TypeDefnCopy struct {
|
||||
FromType string
|
||||
}
|
||||
type AnyScalar struct {
|
||||
Bool *bool
|
||||
String *string
|
||||
Bytes *[]uint8
|
||||
Int *int
|
||||
Float *float64
|
||||
}
|
||||
734
vendor/github.com/ipld/go-ipld-prime/schema/dsl/parse.go
generated
vendored
Normal file
734
vendor/github.com/ipld/go-ipld-prime/schema/dsl/parse.go
generated
vendored
Normal file
@@ -0,0 +1,734 @@
|
||||
package schemadsl
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
dmt "github.com/ipld/go-ipld-prime/schema/dmt"
|
||||
)
|
||||
|
||||
var globalTrue = true
|
||||
|
||||
// TODO: fuzz testing
|
||||
|
||||
func ParseBytes(src []byte) (*dmt.Schema, error) {
|
||||
return Parse("", bytes.NewReader(src))
|
||||
}
|
||||
|
||||
func ParseFile(path string) (*dmt.Schema, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return Parse(path, f)
|
||||
}
|
||||
|
||||
func Parse(name string, r io.Reader) (*dmt.Schema, error) {
|
||||
p := &parser{
|
||||
path: name,
|
||||
br: bufio.NewReader(r),
|
||||
line: 1,
|
||||
col: 1,
|
||||
}
|
||||
|
||||
sch := &dmt.Schema{}
|
||||
sch.Types.Values = make(map[string]dmt.TypeDefn)
|
||||
|
||||
for {
|
||||
tok, err := p.consumeToken()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
switch tok {
|
||||
case "type":
|
||||
name, err := p.consumeName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defn, err := p.typeDefn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mapAppend(&sch.Types, name, defn)
|
||||
case "advanced":
|
||||
return nil, p.errf("TODO: advanced")
|
||||
default:
|
||||
return nil, p.errf("unexpected token: %q", tok)
|
||||
}
|
||||
}
|
||||
return sch, nil
|
||||
}
|
||||
|
||||
func mapAppend(mapPtr, k, v interface{}) {
|
||||
// TODO: delete with generics
|
||||
// TODO: error on dupes
|
||||
|
||||
mval := reflect.ValueOf(mapPtr).Elem()
|
||||
kval := reflect.ValueOf(k)
|
||||
vval := reflect.ValueOf(v)
|
||||
|
||||
keys := mval.FieldByName("Keys")
|
||||
keys.Set(reflect.Append(keys, kval))
|
||||
|
||||
values := mval.FieldByName("Values")
|
||||
if values.IsNil() {
|
||||
values.Set(reflect.MakeMap(values.Type()))
|
||||
}
|
||||
values.SetMapIndex(kval, vval)
|
||||
}
|
||||
|
||||
type parser struct {
|
||||
path string
|
||||
br *bufio.Reader
|
||||
|
||||
peekedToken string
|
||||
|
||||
line, col int
|
||||
}
|
||||
|
||||
func (p *parser) forwardError(err error) error {
|
||||
var prefix string
|
||||
if p.path != "" {
|
||||
prefix = p.path + ":"
|
||||
}
|
||||
return fmt.Errorf("%s%d:%d: %s", prefix, p.line, p.col, err)
|
||||
}
|
||||
|
||||
func (p *parser) errf(format string, args ...interface{}) error {
|
||||
return p.forwardError(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
func (p *parser) consumeToken() (string, error) {
|
||||
if tok := p.peekedToken; tok != "" {
|
||||
p.peekedToken = ""
|
||||
return tok, nil
|
||||
}
|
||||
for {
|
||||
// TODO: use runes for better unicode support
|
||||
b, err := p.br.ReadByte()
|
||||
if err == io.EOF {
|
||||
return "", err // TODO: ErrUnexpectedEOF?
|
||||
}
|
||||
if err != nil {
|
||||
return "", p.forwardError(err)
|
||||
}
|
||||
p.col++
|
||||
switch b {
|
||||
case ' ', '\t', '\r': // skip whitespace
|
||||
continue
|
||||
case '\n': // skip newline
|
||||
// TODO: should we require a newline after each type def, struct field, etc?
|
||||
p.line++
|
||||
p.col = 1
|
||||
continue
|
||||
case '"': // quoted string
|
||||
quoted, err := p.br.ReadString('"')
|
||||
if err != nil {
|
||||
return "", p.forwardError(err)
|
||||
}
|
||||
return "\"" + quoted, nil
|
||||
case '{', '}', '[', ']', '(', ')', ':', '&': // simple token
|
||||
return string(b), nil
|
||||
case '#': // comment
|
||||
_, err := p.br.ReadString('\n')
|
||||
if err != nil {
|
||||
return "", p.forwardError(err)
|
||||
}
|
||||
// tokenize the newline
|
||||
if err := p.br.UnreadByte(); err != nil {
|
||||
panic(err) // should never happen
|
||||
}
|
||||
continue
|
||||
default: // string token or name
|
||||
var sb strings.Builder
|
||||
sb.WriteByte(b)
|
||||
for {
|
||||
b, err := p.br.ReadByte()
|
||||
if err == io.EOF {
|
||||
// Token ends at the end of the whole input.
|
||||
return sb.String(), nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", p.forwardError(err)
|
||||
}
|
||||
// TODO: should probably allow unicode letters and numbers, like Go?
|
||||
switch {
|
||||
case b >= 'a' && b <= 'z', b >= 'A' && b <= 'Z':
|
||||
case b >= '0' && b <= '9':
|
||||
case b == '_':
|
||||
default:
|
||||
if err := p.br.UnreadByte(); err != nil {
|
||||
panic(err) // should never happen
|
||||
}
|
||||
return sb.String(), nil
|
||||
}
|
||||
sb.WriteByte(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) consumePeeked() {
|
||||
if p.peekedToken == "" {
|
||||
panic("consumePeeked requires a peeked token to be present")
|
||||
}
|
||||
p.peekedToken = ""
|
||||
}
|
||||
|
||||
func (p *parser) peekToken() (string, error) {
|
||||
if tok := p.peekedToken; tok != "" {
|
||||
return tok, nil
|
||||
}
|
||||
tok, err := p.consumeToken()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
// peekToken is often used when a token is optional.
|
||||
// If we hit io.EOF, that's not an error.
|
||||
// TODO: consider making peekToken just not return an error?
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
p.peekedToken = tok
|
||||
return tok, nil
|
||||
}
|
||||
|
||||
func (p *parser) consumeName() (string, error) {
|
||||
tok, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch tok {
|
||||
case "\"", "{", "}", "[", "]", "(", ")", ":":
|
||||
return "", p.errf("expected a name, got %q", tok)
|
||||
}
|
||||
if tok[0] == '"' {
|
||||
return "", p.errf("expected a name, got string %s", tok)
|
||||
}
|
||||
return tok, nil
|
||||
}
|
||||
|
||||
func (p *parser) consumeString() (string, error) {
|
||||
tok, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if tok[0] != '"' {
|
||||
return "", p.errf("expected a string, got %q", tok)
|
||||
}
|
||||
// Unquote, too.
|
||||
return tok[1 : len(tok)-1], nil
|
||||
}
|
||||
|
||||
func (p *parser) consumeStringMap() (map[string]string, error) {
|
||||
result := map[string]string{}
|
||||
loop:
|
||||
for {
|
||||
tok, err := p.peekToken()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
switch tok {
|
||||
case "{":
|
||||
p.consumePeeked()
|
||||
case "}":
|
||||
p.consumePeeked()
|
||||
break loop
|
||||
default:
|
||||
key, err := p.consumeName()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
value, err := p.consumeString()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *parser) consumeRequired(tok string) error {
|
||||
got, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if got != tok {
|
||||
return p.errf("expected %q, got %q", tok, got)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *parser) typeDefn() (dmt.TypeDefn, error) {
|
||||
var defn dmt.TypeDefn
|
||||
kind, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return defn, err
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case "struct":
|
||||
if err := p.consumeRequired("{"); err != nil {
|
||||
return defn, err
|
||||
}
|
||||
defn.TypeDefnStruct, err = p.typeStruct()
|
||||
case "union":
|
||||
if err := p.consumeRequired("{"); err != nil {
|
||||
return defn, err
|
||||
}
|
||||
defn.TypeDefnUnion, err = p.typeUnion()
|
||||
case "enum":
|
||||
if err := p.consumeRequired("{"); err != nil {
|
||||
return defn, err
|
||||
}
|
||||
defn.TypeDefnEnum, err = p.typeEnum()
|
||||
case "bool":
|
||||
defn.TypeDefnBool = &dmt.TypeDefnBool{}
|
||||
case "bytes":
|
||||
defn.TypeDefnBytes = &dmt.TypeDefnBytes{}
|
||||
case "float":
|
||||
defn.TypeDefnFloat = &dmt.TypeDefnFloat{}
|
||||
case "int":
|
||||
defn.TypeDefnInt = &dmt.TypeDefnInt{}
|
||||
case "link":
|
||||
defn.TypeDefnLink = &dmt.TypeDefnLink{}
|
||||
case "any":
|
||||
defn.TypeDefnAny = &dmt.TypeDefnAny{}
|
||||
case "&":
|
||||
target, err := p.consumeName()
|
||||
if err != nil {
|
||||
return defn, err
|
||||
}
|
||||
defn.TypeDefnLink = &dmt.TypeDefnLink{ExpectedType: &target}
|
||||
case "string":
|
||||
defn.TypeDefnString = &dmt.TypeDefnString{}
|
||||
case "{":
|
||||
defn.TypeDefnMap, err = p.typeMap()
|
||||
case "[":
|
||||
defn.TypeDefnList, err = p.typeList()
|
||||
case "=":
|
||||
from, err := p.consumeName()
|
||||
if err != nil {
|
||||
return defn, err
|
||||
}
|
||||
defn.TypeDefnCopy = &dmt.TypeDefnCopy{FromType: from}
|
||||
default:
|
||||
err = p.errf("unknown type keyword: %q", kind)
|
||||
}
|
||||
|
||||
return defn, err
|
||||
}
|
||||
|
||||
func (p *parser) typeStruct() (*dmt.TypeDefnStruct, error) {
|
||||
repr := &dmt.StructRepresentation_Map{}
|
||||
repr.Fields = &dmt.Map__FieldName__StructRepresentation_Map_FieldDetails{}
|
||||
|
||||
defn := &dmt.TypeDefnStruct{}
|
||||
for {
|
||||
tok, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tok == "}" {
|
||||
break
|
||||
}
|
||||
name := tok
|
||||
|
||||
var field dmt.StructField
|
||||
loop:
|
||||
for {
|
||||
tok, err := p.peekToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch tok {
|
||||
case "optional":
|
||||
if field.Optional != nil {
|
||||
return nil, p.errf("multiple optional keywords")
|
||||
}
|
||||
field.Optional = &globalTrue
|
||||
p.consumePeeked()
|
||||
case "nullable":
|
||||
if field.Nullable != nil {
|
||||
return nil, p.errf("multiple nullable keywords")
|
||||
}
|
||||
field.Nullable = &globalTrue
|
||||
p.consumePeeked()
|
||||
default:
|
||||
var err error
|
||||
field.Type, err = p.typeNameOrInlineDefn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break loop
|
||||
}
|
||||
}
|
||||
tok, err = p.peekToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tok == "(" {
|
||||
details := dmt.StructRepresentation_Map_FieldDetails{}
|
||||
p.consumePeeked()
|
||||
parenLoop:
|
||||
for {
|
||||
tok, err = p.consumeToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch tok {
|
||||
case ")":
|
||||
break parenLoop
|
||||
case "rename":
|
||||
str, err := p.consumeString()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details.Rename = &str
|
||||
case "implicit":
|
||||
scalar, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var anyScalar dmt.AnyScalar
|
||||
switch {
|
||||
case scalar[0] == '"': // string
|
||||
s, err := strconv.Unquote(scalar)
|
||||
if err != nil {
|
||||
return nil, p.forwardError(err)
|
||||
}
|
||||
anyScalar.String = &s
|
||||
case scalar == "true", scalar == "false": // bool
|
||||
t := scalar == "true"
|
||||
anyScalar.Bool = &t
|
||||
case scalar[0] >= '0' && scalar[0] <= '0':
|
||||
n, err := strconv.Atoi(scalar)
|
||||
if err != nil {
|
||||
return nil, p.forwardError(err)
|
||||
}
|
||||
anyScalar.Int = &n
|
||||
default:
|
||||
return nil, p.errf("unsupported implicit scalar: %s", scalar)
|
||||
}
|
||||
|
||||
details.Implicit = &anyScalar
|
||||
}
|
||||
}
|
||||
mapAppend(repr.Fields, name, details)
|
||||
}
|
||||
|
||||
mapAppend(&defn.Fields, name, field)
|
||||
}
|
||||
|
||||
reprName := "map" // default repr
|
||||
if tok, err := p.peekToken(); err == nil && tok == "representation" {
|
||||
p.consumePeeked()
|
||||
name, err := p.consumeName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reprName = name
|
||||
}
|
||||
if reprName != "map" && len(repr.Fields.Keys) > 0 {
|
||||
return nil, p.errf("rename and implicit are only supported for struct map representations")
|
||||
}
|
||||
switch reprName {
|
||||
case "map":
|
||||
if len(repr.Fields.Keys) == 0 {
|
||||
// Fields is optional; omit it if empty.
|
||||
repr.Fields = nil
|
||||
}
|
||||
defn.Representation.StructRepresentation_Map = repr
|
||||
return defn, nil
|
||||
case "tuple":
|
||||
defn.Representation.StructRepresentation_Tuple = &dmt.StructRepresentation_Tuple{}
|
||||
return defn, nil
|
||||
// TODO: support custom fieldorder
|
||||
case "stringjoin":
|
||||
optMap, err := p.consumeStringMap()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
join, hasJoin := optMap["join"]
|
||||
if !hasJoin {
|
||||
return nil, p.errf("no join value provided for stringjoin repr")
|
||||
}
|
||||
defn.Representation.StructRepresentation_Stringjoin = &dmt.StructRepresentation_Stringjoin{
|
||||
Join: join,
|
||||
}
|
||||
return defn, nil
|
||||
default:
|
||||
return nil, p.errf("unknown struct repr: %q", reprName)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) typeNameOrInlineDefn() (dmt.TypeNameOrInlineDefn, error) {
|
||||
var typ dmt.TypeNameOrInlineDefn
|
||||
tok, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return typ, err
|
||||
}
|
||||
|
||||
switch tok {
|
||||
case "&":
|
||||
expectedName, err := p.consumeName()
|
||||
if err != nil {
|
||||
return typ, err
|
||||
}
|
||||
typ.InlineDefn = &dmt.InlineDefn{TypeDefnLink: &dmt.TypeDefnLink{ExpectedType: &expectedName}}
|
||||
case "[":
|
||||
tlist, err := p.typeList()
|
||||
if err != nil {
|
||||
return typ, err
|
||||
}
|
||||
typ.InlineDefn = &dmt.InlineDefn{TypeDefnList: tlist}
|
||||
case "{":
|
||||
tmap, err := p.typeMap()
|
||||
if err != nil {
|
||||
return typ, err
|
||||
}
|
||||
typ.InlineDefn = &dmt.InlineDefn{TypeDefnMap: tmap}
|
||||
default:
|
||||
typ.TypeName = &tok
|
||||
}
|
||||
return typ, nil
|
||||
}
|
||||
|
||||
func (p *parser) typeList() (*dmt.TypeDefnList, error) {
|
||||
defn := &dmt.TypeDefnList{}
|
||||
tok, err := p.peekToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tok == "nullable" {
|
||||
defn.ValueNullable = &globalTrue
|
||||
p.consumePeeked()
|
||||
}
|
||||
|
||||
defn.ValueType, err = p.typeNameOrInlineDefn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := p.consumeRequired("]"); err != nil {
|
||||
return defn, err
|
||||
}
|
||||
|
||||
// TODO: repr
|
||||
return defn, nil
|
||||
}
|
||||
|
||||
func (p *parser) typeMap() (*dmt.TypeDefnMap, error) {
|
||||
defn := &dmt.TypeDefnMap{}
|
||||
|
||||
var err error
|
||||
defn.KeyType, err = p.consumeName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p.consumeRequired(":"); err != nil {
|
||||
return defn, err
|
||||
}
|
||||
|
||||
tok, err := p.peekToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tok == "nullable" {
|
||||
defn.ValueNullable = &globalTrue
|
||||
p.consumePeeked()
|
||||
}
|
||||
|
||||
defn.ValueType, err = p.typeNameOrInlineDefn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := p.consumeRequired("}"); err != nil {
|
||||
return defn, err
|
||||
}
|
||||
|
||||
return defn, nil
|
||||
}
|
||||
|
||||
func (p *parser) typeUnion() (*dmt.TypeDefnUnion, error) {
|
||||
defn := &dmt.TypeDefnUnion{}
|
||||
var reprKeys []string
|
||||
|
||||
for {
|
||||
tok, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tok == "}" {
|
||||
break
|
||||
}
|
||||
if tok != "|" {
|
||||
return nil, p.errf("expected %q or %q, got %q", "}", "|", tok)
|
||||
}
|
||||
var member dmt.UnionMember
|
||||
nameOrInline, err := p.typeNameOrInlineDefn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if nameOrInline.TypeName != nil {
|
||||
member.TypeName = nameOrInline.TypeName
|
||||
} else {
|
||||
if nameOrInline.InlineDefn.TypeDefnLink != nil {
|
||||
member.UnionMemberInlineDefn = &dmt.UnionMemberInlineDefn{TypeDefnLink: nameOrInline.InlineDefn.TypeDefnLink}
|
||||
} else {
|
||||
return nil, p.errf("expected a name or inline link, got neither")
|
||||
}
|
||||
}
|
||||
defn.Members = append(defn.Members, member)
|
||||
|
||||
key, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reprKeys = append(reprKeys, key)
|
||||
}
|
||||
if err := p.consumeRequired("representation"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reprName, err := p.consumeName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch reprName {
|
||||
case "keyed":
|
||||
repr := &dmt.UnionRepresentation_Keyed{}
|
||||
for i, keyStr := range reprKeys {
|
||||
key, err := strconv.Unquote(keyStr)
|
||||
if err != nil {
|
||||
return nil, p.forwardError(err)
|
||||
}
|
||||
mapAppend(repr, key, defn.Members[i])
|
||||
}
|
||||
defn.Representation.UnionRepresentation_Keyed = repr
|
||||
case "kinded":
|
||||
repr := &dmt.UnionRepresentation_Kinded{}
|
||||
// TODO: verify keys are valid kinds? enum should do it for us?
|
||||
for i, key := range reprKeys {
|
||||
mapAppend(repr, key, defn.Members[i])
|
||||
}
|
||||
defn.Representation.UnionRepresentation_Kinded = repr
|
||||
case "stringprefix":
|
||||
repr := &dmt.UnionRepresentation_StringPrefix{
|
||||
Prefixes: dmt.Map__String__TypeName{
|
||||
Values: map[string]string{},
|
||||
},
|
||||
}
|
||||
for i, key := range reprKeys {
|
||||
// unquote prefix string
|
||||
if len(key) < 2 || key[0] != '"' || key[len(key)-1] != '"' {
|
||||
return nil, p.errf("invalid stringprefix %q", key)
|
||||
}
|
||||
key = key[1 : len(key)-1]
|
||||
|
||||
// add prefix to prefixes map
|
||||
repr.Prefixes.Keys = append(repr.Prefixes.Keys, key)
|
||||
repr.Prefixes.Values[key] = *defn.Members[i].TypeName
|
||||
}
|
||||
defn.Representation.UnionRepresentation_StringPrefix = repr
|
||||
default:
|
||||
return nil, p.errf("TODO: union repr %q", reprName)
|
||||
}
|
||||
return defn, nil
|
||||
}
|
||||
|
||||
func (p *parser) typeEnum() (*dmt.TypeDefnEnum, error) {
|
||||
defn := &dmt.TypeDefnEnum{}
|
||||
var reprKeys []string
|
||||
|
||||
for {
|
||||
tok, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tok == "}" {
|
||||
break
|
||||
}
|
||||
if tok != "|" {
|
||||
return nil, p.errf("expected %q or %q, got %q", "}", "|", tok)
|
||||
}
|
||||
name, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defn.Members = append(defn.Members, name)
|
||||
|
||||
if tok, err := p.peekToken(); err == nil && tok == "(" {
|
||||
p.consumePeeked()
|
||||
key, err := p.consumeToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reprKeys = append(reprKeys, key)
|
||||
if err := p.consumeRequired(")"); err != nil {
|
||||
return defn, err
|
||||
}
|
||||
} else {
|
||||
reprKeys = append(reprKeys, "")
|
||||
}
|
||||
}
|
||||
|
||||
reprName := "string" // default repr
|
||||
if tok, err := p.peekToken(); err == nil && tok == "representation" {
|
||||
p.consumePeeked()
|
||||
name, err := p.consumeName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reprName = name
|
||||
}
|
||||
switch reprName {
|
||||
case "string":
|
||||
repr := &dmt.EnumRepresentation_String{}
|
||||
for i, key := range reprKeys {
|
||||
if key == "" {
|
||||
continue // no key; defaults to the name
|
||||
}
|
||||
if key[0] != '"' {
|
||||
return nil, p.errf("enum string representation used with non-string key: %s", key)
|
||||
}
|
||||
unquoted, err := strconv.Unquote(key)
|
||||
if err != nil {
|
||||
return nil, p.forwardError(err)
|
||||
}
|
||||
mapAppend(repr, defn.Members[i], unquoted)
|
||||
}
|
||||
defn.Representation.EnumRepresentation_String = repr
|
||||
case "int":
|
||||
repr := &dmt.EnumRepresentation_Int{}
|
||||
for i, key := range reprKeys {
|
||||
if key[0] != '"' {
|
||||
return nil, p.errf("enum int representation used with non-string key: %s", key)
|
||||
}
|
||||
unquoted, err := strconv.Unquote(key)
|
||||
if err != nil {
|
||||
return nil, p.forwardError(err)
|
||||
}
|
||||
parsed, err := strconv.Atoi(unquoted)
|
||||
if err != nil {
|
||||
return nil, p.forwardError(err)
|
||||
}
|
||||
mapAppend(repr, defn.Members[i], parsed)
|
||||
}
|
||||
defn.Representation.EnumRepresentation_Int = repr
|
||||
default:
|
||||
return nil, p.errf("unknown enum repr: %q", reprName)
|
||||
}
|
||||
return defn, nil
|
||||
}
|
||||
163
vendor/github.com/ipld/go-ipld-prime/schema/errors.go
generated
vendored
Normal file
163
vendor/github.com/ipld/go-ipld-prime/schema/errors.go
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
)
|
||||
|
||||
// TODO: errors in this package remain somewhat slapdash.
|
||||
//
|
||||
// - datamodel.ErrUnmatchable is used as a catch-all in some places, and contains who-knows-what values wrapped in the Reason field.
|
||||
// - sometimes this wraps things like strconv errors... and on the one hand, i'm kinda okay with that; on the other, maybe saying a bit more with types before getting to that kind of shrug would be nice.
|
||||
// - we probably want to use `Type` values, right?
|
||||
// - or do we: because then we probably need a `Repr bool` next to it, or lots of messages would be nonsensical.
|
||||
// - this is *currently* problematic because we don't actually generate type info consts yet. Hopefully soon; but the pain, meanwhile, is... substantial.
|
||||
// - "substantial" is an understatement. it makes incremental development almost impossible because stringifying error reports turn into nil pointer crashes!
|
||||
// - other ipld-wide errors like `datamodel.ErrWrongKind` *sometimes* refer to a TypeName... but don't *have* to, because they also arise at the merely-datamodel level; what would we do with these?
|
||||
// - it's undesirable (not to mention intensely forbidden for import cycle reasons) for those error types to refer to schema.Type.
|
||||
// - if we must have TypeName treated stringily in some cases, is it really useful to use full type info in other cases -- inconsistently?
|
||||
// - regardless of where we end up with this, some sort of an embed for helping deal with munging and printing this would probably be wise.
|
||||
// - generally, whether you should expect an "datamodel.Err*" or a "schema.Err*" from various methods is quite unclear.
|
||||
// - it's possible that we should wrap *all* schema-level errors in a single "datamodel.ErrSchemaNoMatch" error of some kind, to fix the above. (and maybe that's what ErrUnmatchable really is.) as yet undecided.
|
||||
|
||||
// ErrUnmatchable is the error raised when processing data with IPLD Schemas and
|
||||
// finding data which cannot be matched into the schema.
|
||||
// It will be returned by NodeAssemblers and NodeBuilders when they are fed unmatchable data.
|
||||
// As a result, it will also often be seen returned from unmarshalling
|
||||
// when unmarshalling into schema-constrained NodeAssemblers.
|
||||
//
|
||||
// ErrUnmatchable provides the name of the type in the schema that data couldn't be matched to,
|
||||
// and wraps another error as the more detailed reason.
|
||||
type ErrUnmatchable struct {
|
||||
// TypeName will indicate the named type of a node the function was called on.
|
||||
TypeName string
|
||||
|
||||
// Reason must always be present. ErrUnmatchable doesn't say much otherwise.
|
||||
Reason error
|
||||
}
|
||||
|
||||
func (e ErrUnmatchable) Error() string {
|
||||
return fmt.Sprintf("matching data to schema of %s rejected: %s", e.TypeName, e.Reason)
|
||||
}
|
||||
|
||||
// Reasonf returns a new ErrUnmatchable with a Reason field set to the Errorf of the arguments.
|
||||
// It's a helper function for creating untyped error reasons without importing the fmt package.
|
||||
func (e ErrUnmatchable) Reasonf(format string, a ...interface{}) ErrUnmatchable {
|
||||
return ErrUnmatchable{e.TypeName, fmt.Errorf(format, a...)}
|
||||
}
|
||||
|
||||
// Is provides support for Go's standard errors.Is function so that
|
||||
// errors.Is(yourError, ErrUnmatchable) may be used to match the type of error.
|
||||
func (e ErrUnmatchable) Is(err error) bool {
|
||||
_, ok := err.(ErrUnmatchable)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ErrMissingRequiredField is returned when calling 'Finish' on a NodeAssembler
|
||||
// for a Struct that has not has all required fields set.
|
||||
type ErrMissingRequiredField struct {
|
||||
Missing []string
|
||||
}
|
||||
|
||||
func (e ErrMissingRequiredField) Error() string {
|
||||
return "missing required fields: " + strings.Join(e.Missing, ",")
|
||||
}
|
||||
|
||||
// Is provides support for Go's standard errors.Is function so that
|
||||
// errors.Is(yourError, ErrMissingRequiredField) may be used to match the type of error.
|
||||
func (e ErrMissingRequiredField) Is(err error) bool {
|
||||
_, ok := err.(ErrMissingRequiredField)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ErrInvalidKey indicates a key is invalid for some reason.
|
||||
//
|
||||
// This is only possible for typed nodes; specifically, it may show up when
|
||||
// handling struct types, or maps with interesting key types.
|
||||
// (Other kinds of key invalidity that happen for untyped maps
|
||||
// fall under ErrRepeatedMapKey or ErrWrongKind.)
|
||||
// (Union types use ErrInvalidUnionDiscriminant instead of ErrInvalidKey,
|
||||
// even when their representation strategy is maplike.)
|
||||
type ErrInvalidKey struct {
|
||||
// TypeName will indicate the named type of a node the function was called on.
|
||||
TypeName string
|
||||
|
||||
// Key is the key that was rejected.
|
||||
Key datamodel.Node
|
||||
|
||||
// Reason, if set, may provide details (for example, the reason a key couldn't be converted to a type).
|
||||
// If absent, it'll be presumed "no such field".
|
||||
// ErrUnmatchable may show up as a reason for typed maps with complex keys.
|
||||
Reason error
|
||||
}
|
||||
|
||||
func (e ErrInvalidKey) Error() string {
|
||||
if e.Reason == nil {
|
||||
return fmt.Sprintf("invalid key for map %s: %q: no such field", e.TypeName, e.Key)
|
||||
} else {
|
||||
return fmt.Sprintf("invalid key for map %s: %q: %s", e.TypeName, e.Key, e.Reason)
|
||||
}
|
||||
}
|
||||
|
||||
// Is provides support for Go's standard errors.Is function so that
|
||||
// errors.Is(yourError, ErrInvalidKey) may be used to match the type of error.
|
||||
func (e ErrInvalidKey) Is(err error) bool {
|
||||
_, ok := err.(ErrInvalidKey)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ErrNoSuchField may be returned from lookup functions on the Node
|
||||
// interface when a field is requested which doesn't exist,
|
||||
// or from assigning data into on a MapAssembler for a struct
|
||||
// when the key doesn't match a field name in the structure
|
||||
// (or, when assigning data into a ListAssembler and the list size has
|
||||
// reached out of bounds, in case of a struct with list-like representations!).
|
||||
type ErrNoSuchField struct {
|
||||
Type Type
|
||||
|
||||
Field datamodel.PathSegment
|
||||
}
|
||||
|
||||
func (e ErrNoSuchField) Error() string {
|
||||
if e.Type == nil {
|
||||
return fmt.Sprintf("no such field: {typeinfomissing}.%s", e.Field)
|
||||
}
|
||||
return fmt.Sprintf("no such field: %s.%s", e.Type.Name(), e.Field)
|
||||
}
|
||||
|
||||
// Is provides support for Go's standard errors.Is function so that
|
||||
// errors.Is(yourError, ErrNoSuchField) may be used to match the type of error.
|
||||
func (e ErrNoSuchField) Is(err error) bool {
|
||||
_, ok := err.(ErrNoSuchField)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ErrNotUnionStructure means data was fed into a union assembler that can't match the union.
|
||||
//
|
||||
// This could have one of several reasons, which are explained in the detail text:
|
||||
//
|
||||
// - there are too many entries in the map;
|
||||
// - the keys of critical entries aren't found;
|
||||
// - keys are found that aren't any of the expected critical keys;
|
||||
// - etc.
|
||||
//
|
||||
// TypeName is currently a string... see comments at the top of this file for
|
||||
// remarks on the issues we need to address about these identifiers in errors in general.
|
||||
type ErrNotUnionStructure struct {
|
||||
TypeName string
|
||||
|
||||
Detail string
|
||||
}
|
||||
|
||||
func (e ErrNotUnionStructure) Error() string {
|
||||
return fmt.Sprintf("cannot match schema: union structure constraints for %s caused rejection: %s", e.TypeName, e.Detail)
|
||||
}
|
||||
|
||||
// Is provides support for Go's standard errors.Is function so that
|
||||
// errors.Is(yourError, ErrNotUnionStructure) may be used to match the type of error.
|
||||
func (e ErrNotUnionStructure) Is(err error) bool {
|
||||
_, ok := err.(ErrNotUnionStructure)
|
||||
return ok
|
||||
}
|
||||
112
vendor/github.com/ipld/go-ipld-prime/schema/kind.go
generated
vendored
Normal file
112
vendor/github.com/ipld/go-ipld-prime/schema/kind.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
)
|
||||
|
||||
// TypeKind is an enum of kind in the IPLD Schema system.
|
||||
//
|
||||
// Note that schema.TypeKind is distinct from datamodel.Kind!
|
||||
// Schema kinds include concepts such as "struct" and "enum", which are
|
||||
// concepts only introduced by the Schema layer, and not present in the
|
||||
// Data Model layer.
|
||||
type TypeKind uint8
|
||||
|
||||
const (
|
||||
TypeKind_Invalid TypeKind = 0
|
||||
TypeKind_Map TypeKind = '{'
|
||||
TypeKind_List TypeKind = '['
|
||||
TypeKind_Unit TypeKind = '1'
|
||||
TypeKind_Bool TypeKind = 'b'
|
||||
TypeKind_Int TypeKind = 'i'
|
||||
TypeKind_Float TypeKind = 'f'
|
||||
TypeKind_String TypeKind = 's'
|
||||
TypeKind_Bytes TypeKind = 'x'
|
||||
TypeKind_Link TypeKind = '/'
|
||||
TypeKind_Struct TypeKind = '$'
|
||||
TypeKind_Union TypeKind = '^'
|
||||
TypeKind_Enum TypeKind = '%'
|
||||
TypeKind_Any TypeKind = '?'
|
||||
)
|
||||
|
||||
func (k TypeKind) String() string {
|
||||
switch k {
|
||||
case TypeKind_Invalid:
|
||||
return "invalid"
|
||||
case TypeKind_Map:
|
||||
return "map"
|
||||
case TypeKind_Any:
|
||||
return "any"
|
||||
case TypeKind_List:
|
||||
return "list"
|
||||
case TypeKind_Unit:
|
||||
return "unit"
|
||||
case TypeKind_Bool:
|
||||
return "bool"
|
||||
case TypeKind_Int:
|
||||
return "int"
|
||||
case TypeKind_Float:
|
||||
return "float"
|
||||
case TypeKind_String:
|
||||
return "string"
|
||||
case TypeKind_Bytes:
|
||||
return "bytes"
|
||||
case TypeKind_Link:
|
||||
return "link"
|
||||
case TypeKind_Struct:
|
||||
return "struct"
|
||||
case TypeKind_Union:
|
||||
return "union"
|
||||
case TypeKind_Enum:
|
||||
return "enum"
|
||||
default:
|
||||
panic("invalid enumeration value!")
|
||||
}
|
||||
}
|
||||
|
||||
// ActsLike returns a constant from the datamodel.Kind enum describing what
|
||||
// this schema.TypeKind acts like at the Data Model layer.
|
||||
//
|
||||
// Things with similar names are generally conserved
|
||||
// (e.g. "map" acts like "map");
|
||||
// concepts added by the schema layer have to be mapped onto something
|
||||
// (e.g. "struct" acts like "map").
|
||||
//
|
||||
// Note that this mapping describes how a typed Node will *act*, programmatically;
|
||||
// it does not necessarily describe how it will be *serialized*
|
||||
// (for example, a struct will always act like a map, even if it has a tuple
|
||||
// representation strategy and thus becomes a list when serialized).
|
||||
func (k TypeKind) ActsLike() datamodel.Kind {
|
||||
switch k {
|
||||
case TypeKind_Invalid:
|
||||
return datamodel.Kind_Invalid
|
||||
case TypeKind_Map:
|
||||
return datamodel.Kind_Map
|
||||
case TypeKind_List:
|
||||
return datamodel.Kind_List
|
||||
case TypeKind_Unit:
|
||||
return datamodel.Kind_Bool // maps to 'true'. // REVIEW: odd that this doesn't map to 'null'? // TODO this should be standardized in the specs, in a table.
|
||||
case TypeKind_Bool:
|
||||
return datamodel.Kind_Bool
|
||||
case TypeKind_Int:
|
||||
return datamodel.Kind_Int
|
||||
case TypeKind_Float:
|
||||
return datamodel.Kind_Float
|
||||
case TypeKind_String:
|
||||
return datamodel.Kind_String
|
||||
case TypeKind_Bytes:
|
||||
return datamodel.Kind_Bytes
|
||||
case TypeKind_Link:
|
||||
return datamodel.Kind_Link
|
||||
case TypeKind_Struct:
|
||||
return datamodel.Kind_Map // clear enough: fields are keys.
|
||||
case TypeKind_Union:
|
||||
return datamodel.Kind_Map
|
||||
case TypeKind_Enum:
|
||||
return datamodel.Kind_String // 'AsString' is the one clear thing to define.
|
||||
case TypeKind_Any:
|
||||
return datamodel.Kind_Invalid // TODO: maybe ActsLike should return (Kind, bool)
|
||||
default:
|
||||
panic("invalid enumeration value!")
|
||||
}
|
||||
}
|
||||
9
vendor/github.com/ipld/go-ipld-prime/schema/maybe.go
generated
vendored
Normal file
9
vendor/github.com/ipld/go-ipld-prime/schema/maybe.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package schema
|
||||
|
||||
type Maybe uint8
|
||||
|
||||
const (
|
||||
Maybe_Absent = Maybe(0)
|
||||
Maybe_Null = Maybe(1)
|
||||
Maybe_Value = Maybe(2)
|
||||
)
|
||||
220
vendor/github.com/ipld/go-ipld-prime/schema/tmpBuilders.go
generated
vendored
Normal file
220
vendor/github.com/ipld/go-ipld-prime/schema/tmpBuilders.go
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
)
|
||||
|
||||
// Everything in this file is __a temporary hack__ and will be __removed__.
|
||||
//
|
||||
// These methods will only hang around until more of the "ast" packages are finished;
|
||||
// thereafter, building schema.Type and schema.TypeSystem values will only be
|
||||
// possible through first constructing a schema AST, and *then* using Reify(),
|
||||
// which will validate things correctly, cycle-check, cross-link, etc.
|
||||
//
|
||||
// (Meanwhile, we're using these methods in the codegen prototypes.)
|
||||
|
||||
// These methods use Type objects as parameters when pointing to other things,
|
||||
// but this is... turning out consistently problematic.
|
||||
// Even when we're doing this hacky direct-call doesn't-need-to-be-serializable temp stuff,
|
||||
// as written, this doesn't actually let us express cyclic things viably!
|
||||
// The same initialization questions are also going to come up again when we try to make
|
||||
// concrete values in the output of codegen.
|
||||
// Maybe it's actually just a bad idea to have our reified Type types use Type pointers at all.
|
||||
// (I will never get tired of the tongue twisters, evidently.)
|
||||
// I'm not actually using that much, and it's always avoidable (it's trivial to replace with a map lookup bouncing through a 'ts' variable somewhere).
|
||||
// And having the AST gen'd types be... just... the thing... sounds nice. It could save a lot of work.
|
||||
// (It would mean the golang types don't tell you whether the values have been checked for global properties or not, but, eh.)
|
||||
// (It's not really compatible with "Prototype and Type are the same thing for codegen'd stuff", either (or, we need more interfaces, and to *really* lean into them), but maybe that's okay.)
|
||||
|
||||
func SpawnTypeSystem(types ...Type) (*TypeSystem, []error) {
|
||||
ts := TypeSystem{}
|
||||
ts.Init()
|
||||
for _, typ := range types {
|
||||
ts.Accumulate(typ)
|
||||
}
|
||||
if errs := ts.ValidateGraph(); errs != nil {
|
||||
return nil, errs
|
||||
}
|
||||
return &ts, nil
|
||||
}
|
||||
func MustTypeSystem(types ...Type) *TypeSystem {
|
||||
if ts, err := SpawnTypeSystem(types...); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return ts
|
||||
}
|
||||
}
|
||||
|
||||
func SpawnString(name TypeName) *TypeString {
|
||||
return &TypeString{typeBase{name, nil}}
|
||||
}
|
||||
|
||||
func SpawnBool(name TypeName) *TypeBool {
|
||||
return &TypeBool{typeBase{name, nil}}
|
||||
}
|
||||
|
||||
func SpawnInt(name TypeName) *TypeInt {
|
||||
return &TypeInt{typeBase{name, nil}}
|
||||
}
|
||||
|
||||
func SpawnFloat(name TypeName) *TypeFloat {
|
||||
return &TypeFloat{typeBase{name, nil}}
|
||||
}
|
||||
|
||||
func SpawnBytes(name TypeName) *TypeBytes {
|
||||
return &TypeBytes{typeBase{name, nil}}
|
||||
}
|
||||
|
||||
func SpawnLink(name TypeName) *TypeLink {
|
||||
return &TypeLink{typeBase{name, nil}, "", false}
|
||||
}
|
||||
|
||||
func SpawnLinkReference(name TypeName, pointsTo TypeName) *TypeLink {
|
||||
return &TypeLink{typeBase{name, nil}, pointsTo, true}
|
||||
}
|
||||
|
||||
func SpawnList(name TypeName, valueType TypeName, nullable bool) *TypeList {
|
||||
return &TypeList{typeBase{name, nil}, false, valueType, nullable}
|
||||
}
|
||||
|
||||
func SpawnMap(name TypeName, keyType TypeName, valueType TypeName, nullable bool) *TypeMap {
|
||||
return &TypeMap{typeBase{name, nil}, false, keyType, valueType, nullable}
|
||||
}
|
||||
|
||||
func SpawnAny(name TypeName) *TypeAny {
|
||||
return &TypeAny{typeBase{name, nil}}
|
||||
}
|
||||
|
||||
func SpawnStruct(name TypeName, fields []StructField, repr StructRepresentation) *TypeStruct {
|
||||
v := &TypeStruct{
|
||||
typeBase{name, nil},
|
||||
fields,
|
||||
make(map[string]StructField, len(fields)),
|
||||
repr,
|
||||
}
|
||||
for i := range fields {
|
||||
fields[i].parent = v
|
||||
v.fieldsMap[fields[i].name] = fields[i]
|
||||
}
|
||||
switch repr.(type) {
|
||||
case StructRepresentation_Stringjoin:
|
||||
for _, f := range fields {
|
||||
if f.IsMaybe() {
|
||||
panic("neither nullable nor optional is supported on struct stringjoin representation")
|
||||
}
|
||||
}
|
||||
case nil:
|
||||
v.representation = SpawnStructRepresentationMap(nil)
|
||||
}
|
||||
return v
|
||||
}
|
||||
func SpawnStructField(name string, typ TypeName, optional bool, nullable bool) StructField {
|
||||
return StructField{nil /*populated later*/, name, typ, optional, nullable}
|
||||
}
|
||||
func SpawnStructRepresentationMap(renames map[string]string) StructRepresentation_Map {
|
||||
return StructRepresentation_Map{renames, nil}
|
||||
}
|
||||
func SpawnStructRepresentationMap2(renames map[string]string, implicits map[string]ImplicitValue) StructRepresentation_Map {
|
||||
return StructRepresentation_Map{renames, implicits}
|
||||
}
|
||||
func SpawnStructRepresentationTuple() StructRepresentation_Tuple {
|
||||
return StructRepresentation_Tuple{}
|
||||
}
|
||||
func SpawnStructRepresentationStringjoin(delim string) StructRepresentation_Stringjoin {
|
||||
return StructRepresentation_Stringjoin{delim}
|
||||
}
|
||||
|
||||
func SpawnUnion(name TypeName, members []TypeName, repr UnionRepresentation) *TypeUnion {
|
||||
return &TypeUnion{typeBase{name, nil}, members, repr}
|
||||
}
|
||||
func SpawnUnionRepresentationKeyed(table map[string]TypeName) UnionRepresentation_Keyed {
|
||||
return UnionRepresentation_Keyed{table}
|
||||
}
|
||||
func SpawnUnionRepresentationKinded(table map[datamodel.Kind]TypeName) UnionRepresentation_Kinded {
|
||||
return UnionRepresentation_Kinded{table}
|
||||
}
|
||||
func SpawnUnionRepresentationStringprefix(delim string, table map[string]TypeName) UnionRepresentation_Stringprefix {
|
||||
return UnionRepresentation_Stringprefix{delim, table}
|
||||
}
|
||||
|
||||
func SpawnEnum(name TypeName, members []string, repr EnumRepresentation) *TypeEnum {
|
||||
return &TypeEnum{typeBase{name, nil}, members, repr}
|
||||
}
|
||||
|
||||
// The methods relating to TypeSystem are also mutation-heavy and placeholdery.
|
||||
|
||||
func (ts *TypeSystem) Init() {
|
||||
ts.namedTypes = make(map[TypeName]Type)
|
||||
}
|
||||
func (ts *TypeSystem) Accumulate(typ Type) {
|
||||
typ._Type(ts)
|
||||
name := typ.Name()
|
||||
if _, ok := ts.namedTypes[name]; ok {
|
||||
panic(fmt.Sprintf("duplicate type name: %s", name))
|
||||
}
|
||||
ts.namedTypes[name] = typ
|
||||
ts.names = append(ts.names, name)
|
||||
}
|
||||
func (ts TypeSystem) GetTypes() map[TypeName]Type {
|
||||
return ts.namedTypes
|
||||
}
|
||||
func (ts TypeSystem) TypeByName(n string) Type {
|
||||
return ts.namedTypes[n]
|
||||
}
|
||||
func (ts TypeSystem) Names() []TypeName {
|
||||
return ts.names
|
||||
}
|
||||
|
||||
// ValidateGraph checks that all type names referenced are defined.
|
||||
//
|
||||
// It does not do any other validations of individual type's sensibleness
|
||||
// (that should've happened when they were created
|
||||
// (although also note many of those validates are NYI,
|
||||
// and are roadmapped for after we research self-hosting)).
|
||||
func (ts TypeSystem) ValidateGraph() []error {
|
||||
var ee []error
|
||||
for tn, t := range ts.namedTypes {
|
||||
switch t2 := t.(type) {
|
||||
case *TypeBool,
|
||||
*TypeInt,
|
||||
*TypeFloat,
|
||||
*TypeString,
|
||||
*TypeBytes,
|
||||
*TypeEnum:
|
||||
continue // nothing to check: these are leaf nodes and refer to no other types.
|
||||
case *TypeLink:
|
||||
if !t2.hasReferencedType {
|
||||
continue
|
||||
}
|
||||
if _, ok := ts.namedTypes[t2.referencedType]; !ok {
|
||||
ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as link reference type)", tn, t2.referencedType))
|
||||
}
|
||||
case *TypeStruct:
|
||||
for _, f := range t2.fields {
|
||||
if _, ok := ts.namedTypes[f.typ]; !ok {
|
||||
ee = append(ee, fmt.Errorf("type %s refers to missing type %s (in field %q)", tn, f.typ, f.name))
|
||||
}
|
||||
}
|
||||
case *TypeMap:
|
||||
if _, ok := ts.namedTypes[t2.keyType]; !ok {
|
||||
ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as key type)", tn, t2.keyType))
|
||||
}
|
||||
if _, ok := ts.namedTypes[t2.valueType]; !ok {
|
||||
ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as value type)", tn, t2.valueType))
|
||||
}
|
||||
case *TypeList:
|
||||
if _, ok := ts.namedTypes[t2.valueType]; !ok {
|
||||
ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as value type)", tn, t2.valueType))
|
||||
}
|
||||
case *TypeUnion:
|
||||
for _, mn := range t2.members {
|
||||
if _, ok := ts.namedTypes[mn]; !ok {
|
||||
ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as a member)", tn, mn))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ee
|
||||
}
|
||||
270
vendor/github.com/ipld/go-ipld-prime/schema/type.go
generated
vendored
Normal file
270
vendor/github.com/ipld/go-ipld-prime/schema/type.go
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
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_StringPairs) _StructRepresentation() {}
|
||||
func (StructRepresentation_Stringjoin) _StructRepresentation() {}
|
||||
|
||||
type StructRepresentation_Map struct {
|
||||
renames map[string]string
|
||||
implicits map[string]ImplicitValue
|
||||
}
|
||||
type StructRepresentation_Tuple 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
|
||||
287
vendor/github.com/ipld/go-ipld-prime/schema/typeMethods.go
generated
vendored
Normal file
287
vendor/github.com/ipld/go-ipld-prime/schema/typeMethods.go
generated
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
)
|
||||
|
||||
/* cookie-cutter standard interface stuff */
|
||||
|
||||
func (t *typeBase) _Type(ts *TypeSystem) {
|
||||
t.universe = ts
|
||||
}
|
||||
func (t typeBase) TypeSystem() *TypeSystem { return t.universe }
|
||||
func (t typeBase) Name() TypeName { return t.name }
|
||||
|
||||
func (TypeBool) TypeKind() TypeKind { return TypeKind_Bool }
|
||||
func (TypeString) TypeKind() TypeKind { return TypeKind_String }
|
||||
func (TypeBytes) TypeKind() TypeKind { return TypeKind_Bytes }
|
||||
func (TypeInt) TypeKind() TypeKind { return TypeKind_Int }
|
||||
func (TypeFloat) TypeKind() TypeKind { return TypeKind_Float }
|
||||
func (TypeAny) TypeKind() TypeKind { return TypeKind_Any }
|
||||
func (TypeMap) TypeKind() TypeKind { return TypeKind_Map }
|
||||
func (TypeList) TypeKind() TypeKind { return TypeKind_List }
|
||||
func (TypeLink) TypeKind() TypeKind { return TypeKind_Link }
|
||||
func (TypeUnion) TypeKind() TypeKind { return TypeKind_Union }
|
||||
func (TypeStruct) TypeKind() TypeKind { return TypeKind_Struct }
|
||||
func (TypeEnum) TypeKind() TypeKind { return TypeKind_Enum }
|
||||
|
||||
func (TypeBool) RepresentationBehavior() datamodel.Kind { return datamodel.Kind_Bool }
|
||||
func (TypeString) RepresentationBehavior() datamodel.Kind { return datamodel.Kind_String }
|
||||
func (TypeBytes) RepresentationBehavior() datamodel.Kind { return datamodel.Kind_Bytes }
|
||||
func (TypeInt) RepresentationBehavior() datamodel.Kind { return datamodel.Kind_Int }
|
||||
func (TypeFloat) RepresentationBehavior() datamodel.Kind { return datamodel.Kind_Float }
|
||||
func (TypeMap) RepresentationBehavior() datamodel.Kind { return datamodel.Kind_Map }
|
||||
func (TypeList) RepresentationBehavior() datamodel.Kind { return datamodel.Kind_List }
|
||||
func (TypeLink) RepresentationBehavior() datamodel.Kind { return datamodel.Kind_Link }
|
||||
func (t TypeUnion) RepresentationBehavior() datamodel.Kind {
|
||||
switch t.representation.(type) {
|
||||
case UnionRepresentation_Keyed:
|
||||
return datamodel.Kind_Map
|
||||
case UnionRepresentation_Kinded:
|
||||
return datamodel.Kind_Invalid // you can't know with this one, until you see the value (and thus can its inhabitant's behavior)!
|
||||
case UnionRepresentation_Envelope:
|
||||
return datamodel.Kind_Map
|
||||
case UnionRepresentation_Inline:
|
||||
return datamodel.Kind_Map
|
||||
case UnionRepresentation_Stringprefix:
|
||||
return datamodel.Kind_String
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
func (t TypeStruct) RepresentationBehavior() datamodel.Kind {
|
||||
switch t.representation.(type) {
|
||||
case StructRepresentation_Map:
|
||||
return datamodel.Kind_Map
|
||||
case StructRepresentation_Tuple:
|
||||
return datamodel.Kind_List
|
||||
case StructRepresentation_StringPairs:
|
||||
return datamodel.Kind_String
|
||||
case StructRepresentation_Stringjoin:
|
||||
return datamodel.Kind_String
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
func (t TypeEnum) RepresentationBehavior() datamodel.Kind {
|
||||
// TODO: this should have a representation strategy switch too; sometimes that will indicate int representation behavior.
|
||||
return datamodel.Kind_String
|
||||
}
|
||||
func (t TypeAny) RepresentationBehavior() datamodel.Kind {
|
||||
return datamodel.Kind_Invalid // TODO: what can we possibly do here?
|
||||
}
|
||||
|
||||
/* interesting methods per Type type */
|
||||
|
||||
// beware: many of these methods will change when we successfully bootstrap self-hosting.
|
||||
//
|
||||
// The current methods return reified Type objects; in the future, there might be less of that.
|
||||
// Returning reified Type objects requires bouncing lookups through the typesystem map;
|
||||
// this is unavoidable because we need to handle cycles in definitions.
|
||||
// However, the extra (and cyclic) pointers that requires won't necessarily jive well if
|
||||
// we remake the Type types to have close resemblances to the Data Model tree data.)
|
||||
//
|
||||
// It's also unfortunate that some of the current methods collide in name with
|
||||
// the names of the Data Model fields. We might reshuffling things to reduce this.
|
||||
//
|
||||
// At any rate, all of these changes will come as a sweep once we
|
||||
// get a self-hosting gen of the schema-schema, not before
|
||||
// (the effort of updating template references is substantial).
|
||||
|
||||
// IsAnonymous is returns true if the type was unnamed. Unnamed types will
|
||||
// claim to have a Name property like `{Foo:Bar}`, and this is not guaranteed
|
||||
// to be a unique string for all types in the universe.
|
||||
func (t TypeMap) IsAnonymous() bool {
|
||||
return t.anonymous
|
||||
}
|
||||
|
||||
// KeyType returns the Type of the map keys.
|
||||
//
|
||||
// Note that map keys will must always be some type which is representable as a
|
||||
// string in the IPLD Data Model (e.g. either TypeString or TypeEnum).
|
||||
func (t TypeMap) KeyType() Type {
|
||||
return t.universe.namedTypes[t.keyType]
|
||||
}
|
||||
|
||||
// ValueType returns the Type of the map values.
|
||||
func (t TypeMap) ValueType() Type {
|
||||
return t.universe.namedTypes[t.valueType]
|
||||
}
|
||||
|
||||
// ValueIsNullable returns a bool describing if the map values are permitted
|
||||
// to be null.
|
||||
func (t TypeMap) ValueIsNullable() bool {
|
||||
return t.valueNullable
|
||||
}
|
||||
|
||||
// IsAnonymous is returns true if the type was unnamed. Unnamed types will
|
||||
// claim to have a Name property like `[Foo]`, and this is not guaranteed
|
||||
// to be a unique string for all types in the universe.
|
||||
func (t TypeList) IsAnonymous() bool {
|
||||
return t.anonymous
|
||||
}
|
||||
|
||||
// ValueType returns to the Type of the list values.
|
||||
func (t TypeList) ValueType() Type {
|
||||
return t.universe.namedTypes[t.valueType]
|
||||
}
|
||||
|
||||
// ValueIsNullable returns a bool describing if the list values are permitted
|
||||
// to be null.
|
||||
func (t TypeList) ValueIsNullable() bool {
|
||||
return t.valueNullable
|
||||
}
|
||||
|
||||
// Members returns the list of all types that are possible inhabitants of this union.
|
||||
func (t TypeUnion) Members() []Type {
|
||||
a := make([]Type, len(t.members))
|
||||
for i := range t.members {
|
||||
a[i] = t.universe.namedTypes[t.members[i]]
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (t TypeUnion) RepresentationStrategy() UnionRepresentation {
|
||||
return t.representation
|
||||
}
|
||||
|
||||
func (r UnionRepresentation_Keyed) GetDiscriminant(t Type) string {
|
||||
for d, t2 := range r.table {
|
||||
if t2 == t.Name() {
|
||||
return d
|
||||
}
|
||||
}
|
||||
panic("that type isn't a member of this union")
|
||||
}
|
||||
|
||||
func (r UnionRepresentation_Stringprefix) GetDelim() string {
|
||||
return r.delim
|
||||
}
|
||||
|
||||
func (r UnionRepresentation_Stringprefix) GetDiscriminant(t Type) string {
|
||||
for d, t2 := range r.table {
|
||||
if t2 == t.Name() {
|
||||
return d
|
||||
}
|
||||
}
|
||||
panic("that type isn't a member of this union")
|
||||
}
|
||||
|
||||
// GetMember returns type info for the member matching the kind argument,
|
||||
// or may return nil if that kind is not mapped to a member of this union.
|
||||
func (r UnionRepresentation_Kinded) GetMember(k datamodel.Kind) TypeName {
|
||||
return r.table[k]
|
||||
}
|
||||
|
||||
// Fields returns a slice of descriptions of the object's fields.
|
||||
func (t TypeStruct) Fields() []StructField {
|
||||
return t.fields
|
||||
}
|
||||
|
||||
// Field looks up a StructField by name, or returns nil if no such field.
|
||||
func (t TypeStruct) Field(name string) *StructField {
|
||||
if v, ok := t.fieldsMap[name]; ok {
|
||||
return &v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parent returns the type information that this field describes a part of.
|
||||
//
|
||||
// While in many cases, you may know the parent already from context,
|
||||
// there may still be situations where want to pass around a field and
|
||||
// not need to continue passing down the parent type with it; this method
|
||||
// helps your code be less redundant in such a situation.
|
||||
// (You'll find this useful for looking up any rename directives, for example,
|
||||
// when holding onto a field, since that requires looking up information from
|
||||
// the representation strategy, which is a property of the type as a whole.)
|
||||
func (f StructField) Parent() *TypeStruct { return f.parent }
|
||||
|
||||
// Name returns the string name of this field. The name is the string that
|
||||
// will be used as a map key if the structure this field is a member of is
|
||||
// serialized as a map representation.
|
||||
func (f StructField) Name() string { return f.name }
|
||||
|
||||
// Type returns the Type of this field's value. Note the field may
|
||||
// also be unset if it is either Optional or Nullable.
|
||||
func (f StructField) Type() Type { return f.parent.universe.namedTypes[f.typ] }
|
||||
|
||||
// IsOptional returns true if the field is allowed to be absent from the object.
|
||||
// If IsOptional is false, the field may be absent from the serial representation
|
||||
// of the object entirely.
|
||||
//
|
||||
// Note being optional is different than saying the value is permitted to be null!
|
||||
// A field may be both nullable and optional simultaneously, or either, or neither.
|
||||
func (f StructField) IsOptional() bool { return f.optional }
|
||||
|
||||
// IsNullable returns true if the field value is allowed to be null.
|
||||
//
|
||||
// If is Nullable is false, note that it's still possible that the field value
|
||||
// will be absent if the field is Optional! Being nullable is unrelated to
|
||||
// whether the field's presence is optional as a whole.
|
||||
//
|
||||
// Note that a field may be both nullable and optional simultaneously,
|
||||
// or either, or neither.
|
||||
func (f StructField) IsNullable() bool { return f.nullable }
|
||||
|
||||
// IsMaybe returns true if the field value is allowed to be either null or absent.
|
||||
//
|
||||
// This is a simple "or" of the two properties,
|
||||
// but this method is a shorthand that turns out useful often.
|
||||
func (f StructField) IsMaybe() bool { return f.nullable || f.optional }
|
||||
|
||||
func (t TypeStruct) RepresentationStrategy() StructRepresentation {
|
||||
return t.representation
|
||||
}
|
||||
|
||||
func (r StructRepresentation_Map) GetFieldKey(field StructField) string {
|
||||
if n, ok := r.renames[field.name]; ok {
|
||||
return n
|
||||
}
|
||||
return field.name
|
||||
}
|
||||
|
||||
func (r StructRepresentation_Map) FieldHasRename(field StructField) bool {
|
||||
_, ok := r.renames[field.name]
|
||||
return ok
|
||||
}
|
||||
|
||||
// FieldImplicit returns the 'implicit' value for a field, or nil, if there isn't one.
|
||||
//
|
||||
// Because this returns the golang ImplicitValue type, which is an interface,
|
||||
// golang type switching is needed to distinguish what it holds.
|
||||
// (In other words, be warned that this function is not very friendly to use from templating engines.)
|
||||
func (r StructRepresentation_Map) FieldImplicit(field StructField) ImplicitValue {
|
||||
if r.implicits == nil {
|
||||
return nil
|
||||
}
|
||||
return r.implicits[field.name]
|
||||
}
|
||||
|
||||
func (r StructRepresentation_Stringjoin) GetDelim() string {
|
||||
return r.sep
|
||||
}
|
||||
|
||||
// Members returns a slice the strings which are valid inhabitants of this enum.
|
||||
func (t TypeEnum) Members() []string {
|
||||
return t.members
|
||||
}
|
||||
|
||||
func (t TypeEnum) RepresentationStrategy() EnumRepresentation {
|
||||
return t.representation
|
||||
}
|
||||
|
||||
// Links can keep a referenced type, which is a hint only about the data on the
|
||||
// other side of the link, no something that can be explicitly validated without
|
||||
// loading the link
|
||||
|
||||
// HasReferencedType returns true if the link has a hint about the type it references
|
||||
// false if it's generic
|
||||
func (t TypeLink) HasReferencedType() bool {
|
||||
return t.hasReferencedType
|
||||
}
|
||||
|
||||
// ReferencedType returns the type hint for the node on the other side of the link
|
||||
func (t TypeLink) ReferencedType() Type {
|
||||
return t.universe.namedTypes[t.referencedType]
|
||||
}
|
||||
85
vendor/github.com/ipld/go-ipld-prime/schema/typedNode.go
generated
vendored
Normal file
85
vendor/github.com/ipld/go-ipld-prime/schema/typedNode.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"github.com/ipld/go-ipld-prime/datamodel"
|
||||
)
|
||||
|
||||
// schema.TypedNode is a superset of the datamodel.Node interface, and has additional behaviors.
|
||||
//
|
||||
// A schema.TypedNode can be inspected for its schema.Type and schema.TypeKind,
|
||||
// which conveys much more and richer information than the Data Model layer
|
||||
// datamodel.Kind.
|
||||
//
|
||||
// There are many different implementations of schema.TypedNode.
|
||||
// One implementation can wrap any other existing datamodel.Node (i.e., it's zero-copy)
|
||||
// and promises that it has *already* been validated to match the typesystem.Type;
|
||||
// another implementation similarly wraps any other existing datamodel.Node, but
|
||||
// defers to the typesystem validation checking to fields that are accessed;
|
||||
// and when using code generation tools, all of the generated native Golang
|
||||
// types produced by the codegen will each individually implement schema.TypedNode.
|
||||
//
|
||||
// Typed nodes sometimes have slightly different behaviors than plain nodes:
|
||||
// For example, when looking up fields on a typed node that's a struct,
|
||||
// the error returned for a lookup with a key that's not a field name will
|
||||
// be ErrNoSuchField (instead of ErrNotExists).
|
||||
// These behaviors apply to the schema.TypedNode only and not their representations;
|
||||
// continuing the example, the .Representation().LookupByString() method on
|
||||
// that same node for the same key as plain `.LookupByString()` will still
|
||||
// return ErrNotExists, because the representation isn't a schema.TypedNode!
|
||||
type TypedNode interface {
|
||||
// schema.TypedNode acts just like a regular Node for almost all purposes;
|
||||
// which datamodel.Kind it acts as is determined by the TypeKind.
|
||||
// (Note that the representation strategy of the type does *not* affect
|
||||
// the Kind of schema.TypedNode -- rather, the representation strategy
|
||||
// affects the `.Representation().Kind()`.)
|
||||
//
|
||||
// For example: if the `.Type().TypeKind()` of this node is "struct",
|
||||
// it will act like Kind() == "map"
|
||||
// (even if Type().(Struct).ReprStrategy() is "tuple").
|
||||
datamodel.Node
|
||||
|
||||
// Type returns a reference to the reified schema.Type value.
|
||||
Type() Type
|
||||
|
||||
// Representation returns a datamodel.Node which sees the data in this node
|
||||
// in its representation form.
|
||||
//
|
||||
// For example: if the `.Type().TypeKind()` of this node is "struct",
|
||||
// `.Representation().TypeKind()` may vary based on its representation strategy:
|
||||
// if the representation strategy is "map", then it will be Kind=="map";
|
||||
// if the streatgy is "tuple", then it will be Kind=="list".
|
||||
Representation() datamodel.Node
|
||||
}
|
||||
|
||||
// schema.TypedLinkNode is a superset of the schema.TypedNode interface, and has one additional behavior.
|
||||
//
|
||||
// A schema.TypedLinkNode contains a hint for the appropriate node builder to use for loading data
|
||||
// on the other side of the link contained within the node, so that it can be assembled
|
||||
// into a node representation and validated against the schema as quickly as possible
|
||||
//
|
||||
// So, for example, if you wanted to support loading the other side of a link
|
||||
// with a code-gen'd node builder while utilizing the automatic loading facilities
|
||||
// of the traversal package, you could write a LinkNodeBuilderChooser as follows:
|
||||
//
|
||||
// func LinkNodeBuilderChooser(lnk datamodel.Link, lnkCtx linking.LinkContext) datamodel.NodePrototype {
|
||||
// if tlnkNd, ok := lnkCtx.LinkNode.(schema.TypedLinkNode); ok {
|
||||
// return tlnkNd.LinkTargetNodePrototype()
|
||||
// }
|
||||
// return basicnode.Prototype.Any
|
||||
// }
|
||||
type TypedLinkNode interface {
|
||||
LinkTargetNodePrototype() datamodel.NodePrototype
|
||||
}
|
||||
|
||||
// TypedPrototype is a superset of the datamodel.Nodeprototype interface, and has
|
||||
// additional behaviors, much like TypedNode for datamodel.Node.
|
||||
type TypedPrototype interface {
|
||||
datamodel.NodePrototype
|
||||
|
||||
// Type returns a reference to the reified schema.Type value.
|
||||
Type() Type
|
||||
|
||||
// Representation returns a datamodel.NodePrototype for the representation
|
||||
// form of the prototype.
|
||||
Representation() datamodel.NodePrototype
|
||||
}
|
||||
18
vendor/github.com/ipld/go-ipld-prime/schema/typesystem.go
generated
vendored
Normal file
18
vendor/github.com/ipld/go-ipld-prime/schema/typesystem.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package schema
|
||||
|
||||
type TypeSystem struct {
|
||||
// namedTypes is the set of all named types in this universe.
|
||||
// The map's key is the value's Name() property and must be unique.
|
||||
//
|
||||
// The IsAnonymous property is false for all values in this map that
|
||||
// support the IsAnonymous property.
|
||||
//
|
||||
// Each Type in the universe may only refer to other types in their
|
||||
// definition if those type are either A) in this namedTypes map,
|
||||
// or B) are IsAnonymous==true.
|
||||
namedTypes map[TypeName]Type
|
||||
|
||||
// names are the same set of names stored in namedTypes,
|
||||
// but in insertion order.
|
||||
names []TypeName
|
||||
}
|
||||
70
vendor/github.com/ipld/go-ipld-prime/schema/validate.go
generated
vendored
Normal file
70
vendor/github.com/ipld/go-ipld-prime/schema/validate.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package schema
|
||||
|
||||
/*
|
||||
Okay, so. There are several fun considerations for a "validate" method.
|
||||
|
||||
---
|
||||
|
||||
There's two radically different approaches to "validate"/"reify":
|
||||
|
||||
- Option 1: Look at the schema.Type info and check if a data node seems
|
||||
to match it -- recursing on the type info.
|
||||
- Option 2: Use the schema.Type{}.RepresentationNodeBuilder() to feed data
|
||||
into it -- recursing on what the nodebuilder already expresses.
|
||||
|
||||
(Option 2 also need to take a `memStorage ipld.NodeBuilder` param, btw,
|
||||
for handling all the cases where we *aren't* doing codegen.)
|
||||
|
||||
Option 1 provides a little more opportunity for returning multiple errors.
|
||||
Option 2 will generally have a hard time with that (nodebuilers are not
|
||||
necessarily in a valid state after their first error encounter).
|
||||
|
||||
As a result of having these two options at all, we may indeed end up with
|
||||
at least two very different functions -- despite seeming to do similar
|
||||
things, their interior will radically diverge.
|
||||
|
||||
---
|
||||
|
||||
We may also need to consider distinct reification paths: we may want one
|
||||
that returns a new node tree which is eagerly converted to schema.TypedNode
|
||||
recursively; and another that returns a lazyNode which wraps things
|
||||
with their typed node constraints only as they're requested.
|
||||
(Note that the latter would have interesting implications for any code
|
||||
which has expectations about pointer equality consistency.)
|
||||
|
||||
---
|
||||
|
||||
A further fun issue which needs consideration: well, I'll just save a snip
|
||||
of prospective docs I wrote while trying to iterate on these functions:
|
||||
|
||||
// Note that using Validate on a node that's already a schema.TypedNode is likely
|
||||
// to be nonsensical. In many schemas, the schema.TypedNode tree is actually a
|
||||
// different depth than its representational tree (e.g. unions can cause this),
|
||||
|
||||
... and that's ... that's a fairly sizable issue that needs resolving.
|
||||
There's a couple of different ways to handle some of the behaviors around
|
||||
unions, and some of them make the tradeoff described above, and I'm really
|
||||
unsure if all the implications have been sussed out yet. We should defer
|
||||
writing code that depends on this issue until gathering some more info.
|
||||
|
||||
---
|
||||
|
||||
One more note: about returning multiple errors from a Validate function:
|
||||
there's an upper bound of the utility of the thing. Going farther than the
|
||||
first parse error is nice, but it will still hit limits: for example,
|
||||
upon encountering a union and failing to match it, we can't generally
|
||||
produce further errors from anywhere deeper in the tree without them being
|
||||
combinatorial "if previous juncture X was type Y, then..." nonsense.
|
||||
(This applies to all recursive kinds to some degree, but it's especially
|
||||
rough with unions. For most of the others, it's flatly a missing field,
|
||||
or an excessive field, or a leaf error; with unions it can be hard to tell.)
|
||||
|
||||
---
|
||||
|
||||
And finally: both "Validate" and "Reify" methods might actually belong
|
||||
in the schema.TypedNode package -- if they make *any* reference to `schema.TypedNode`,
|
||||
then they have no choice (otherwise, cyclic imports would occur).
|
||||
If we make a "Validate" that works purely on the schema.Type info, and
|
||||
returns *only* errors: only then we can have it in the schema package.
|
||||
|
||||
*/
|
||||
Reference in New Issue
Block a user