Commit 122c5338 authored by Eric Myhre's avatar Eric Myhre

Refactor of type/schema code.

- `typed.Node` -> now lives in the `impl/typed` package, more like
other nodes.

- Most of the other essential parts of reasoning about types moved
to `schema` package.  ("typed.Type" seemed like a nasty stutter.)

- `typed.Universe` renamed to `schema.TypeSystem`.

- Current `Validate` method moved to `schema` package, but see new
comments about potential future homes of that code, and its
aspirational relationship to `typed.Node`.

Conspicuously *not* yet refactored or moved in this comment:

- The `typed/declaration` package -- though it will shortly be scrapped
and later reappear as `schema/ast`.  The dream is that it would be
neatest of all if we could generate it by codegen; but we'll see.
(This would seem to imply we'll have to make sufficient exported
methods for creating the `schema.Type` values... while we also want
to make those immutable.  We'll... see.)

- The `typed/gen` package is also untouched in this commit, but
should similarly move shortly.  The codegen really ought to be built
against the `schema.Type` reified interfaces.

Overall, this drops the sheer nesting depths of packages a fair bit,
which seems likely to be a good smell.
parent 5e963cc8
......@@ -2,12 +2,12 @@ package typed
import (
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/typed/system"
"github.com/ipld/go-ipld-prime/schema"
)
// typed.Node is a superset of the ipld.Node interface, and has additional behaviors.
//
// A typed.Node can be inspected for its typesystem.Type and typesystem.Kind,
// A typed.Node can be inspected for its schema.Type and schema.Kind,
// which conveys much more and richer information than the Data Model layer
// ipld.ReprKind.
//
......@@ -26,5 +26,13 @@ import (
type Node interface {
ipld.Node
Type() typesystem.Type
Type() schema.Type
}
// unboxing is... ugh, we probably should codegen an unbox method per concrete type.
// (or, attach them to the non-pointer type, which would namespace in an alloc-free way, but i don't know if that's anything but confusing.)
// there are notes about this from way back at 2019.01; reread to see if any remain relevant and valid.
// main important point is: it's not gonna be casting.
// if casting was sufficient to unbox, it'd mean every method on the Node interface would be difficult to use as a field name on a struct type. undesirable.
// okay, or, alternative, we flip this to `superapi.Footype{}.Fields().FrobFieldName()`. that strikes me as unlikely to be pleasing, though.
// istm we can safely expect direct use of field names much, much more often that flipping back and forth to hypergeneric node; so we should optimize syntax for that accordingly.
package typesystem
package schema
import (
ipld "github.com/ipld/go-ipld-prime"
typedeclaration "github.com/ipld/go-ipld-prime/typed/declaration"
)
type TypeName = typedeclaration.TypeName
type TypeName string // = ast.TypeName
// typesystem.Type is an union interface; each of the `Type*` concrete types
// in this package are one of its members.
......@@ -45,7 +44,7 @@ type Type interface {
_Type()
// Returns a pointer to the typesystem.Universe this type is a member of.
Universe() *Universe
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,
......@@ -79,7 +78,7 @@ var (
type anyType struct {
name TypeName
universe *Universe
universe *TypeSystem
}
type TypeBool struct {
......
package typesystem
package schema
import (
"github.com/ipld/go-ipld-prime"
......@@ -6,9 +6,9 @@ import (
/* cookie-cutter standard interface stuff */
func (anyType) _Type() {}
func (t anyType) Universe() *Universe { return t.universe }
func (t anyType) Name() TypeName { return t.name }
func (anyType) _Type() {}
func (t anyType) TypeSystem() *TypeSystem { return t.universe }
func (t anyType) Name() TypeName { return t.name }
func (TypeBool) ReprKind() ipld.ReprKind {
return ipld.ReprKind_Bool
......
package typesystem
package schema
type Universe struct {
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.
//
......
package typesystem
package schema
import (
"fmt"
......@@ -7,12 +7,21 @@ import (
"github.com/ipld/go-ipld-prime"
)
func Validate(ts Universe, t Type, node ipld.Node) []error {
// FUTURE: we also want something *almost* identical to this Validate method,
// but returning a `typed.Node` in the case of no error.
// (Such a method would go in the same package as `typed.Node`, presumably.)
// How do we avoid writing this method twice?
// Maybe both a Validate and Reify method belong in `typed` package,
// and Validate just returns less?
// No... Reify should probably short-circuit sooner?
// Unclear. Guess first step is that we need to decide the intended UX!
func Validate(ts TypeSystem, t Type, node ipld.Node) []error {
return validate(ts, t, node, "/")
}
// review: 'ts' param might not actually be necessary; everything relevant can be reached from t so far.
func validate(ts Universe, t Type, node ipld.Node, pth string) []error {
func validate(ts TypeSystem, t Type, node ipld.Node, pth string) []error {
switch t2 := t.(type) {
case TypeBool:
if node.ReprKind() != ipld.ReprKind_Bool {
......
package typesystem
package schema
import (
"testing"
......@@ -15,7 +15,7 @@ func TestSimpleTypes(t *testing.T) {
anyType{name: "Foo"},
}
Wish(t,
Validate(Universe{}, t1, n1),
Validate(TypeSystem{}, t1, n1),
ShouldEqual, []error(nil))
})
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment