Commit dc19057d authored by Eric Myhre's avatar Eric Myhre

Add exported accessors for builders + reprbuilders

I'm not sure if I like these symbol names.  Or rather, I don't,
but haven't decided on what would be preferable yet.

There's a couple of options that have come to mind:

- option 1
  - `func {{ .Type.Name }}__NodeBuilder() ipld.NodeBuilder`
  - `func {{ .Type.Name }}__ReprBuilder() ipld.NodeBuilder`

- option 2
  - `func NewBuilderFor{{ .Type.Name }}() ipld.NodeBuilder`
  - `func NewReprBuilderFor{{ .Type.Name }}() ipld.NodeBuilder`

- option 3
  - `func (Builders) {{ .Type.Name }}() ipld.NodeBuilder`
  - `func (ReprBuilders) {{ .Type.Name }}() ipld.NodeBuilder`

Option 3 would make 'Builders' and 'ReprBuilders' effectively reserved
as type names if you're using codegen.  Schemas using them could use
adjunct config specific to golang to rename things out of conflict in
the generated code, but it's still a potential friction.

Option 2 would also have some naming collision hijinx to worry about,
on further though.  Only Option 1 is immune, by virtue of using "__"
in combination with the schema rule that type names can't contain "__".

This diff is implementing Option 1.  I think I'm partial to Option 3,
but not quite confident enough in it to lunge for it yet.

Putting more methods on the *concrete* types would also be another
interesting fourth option!  These methods would ignore the actual
value, and typically be used on the zero value: e.g., usage would
resemble `Foo{}.ReprBuilder()`.
The upside of this would be we'd then have no package scoped exported
symbols except exactly the set matching type names in the schema.
However, the opportunities for confusion with this would be numerous:
we couldn't use the 'NodeBuilder' method name (because that's the
potentially-stateful/COW one), but would still be returning a
NodeBuilder type?  Etc.  Might not be good.

More to think about here in the future.
Signed-off-by: default avatarEric Myhre <hash@exultant.us>
parent ec1434e7
......@@ -45,7 +45,7 @@ func TestScalarUnmarshal(t *testing.T) {
tb := &TokenSourceBucket{tokens: []tok.Token{
{Type: tok.TString, Str: "zooooom"},
}}
nb := _String__NodeBuilder{}
nb := String__NodeBuilder()
n, err := encoding.Unmarshal(nb, tb)
Wish(t, err, ShouldEqual, nil)
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_String)
......@@ -66,28 +66,28 @@ func TestGeneratedStructs(t *testing.T) {
)
t.Run("type-level build and read", func(t *testing.T) {
t.Run("all fields set", func(t *testing.T) {
mb, err := _Stroct__NodeBuilder{}.CreateMap()
mb, err := Stroct__NodeBuilder().CreateMap()
Require(t, err, ShouldEqual, nil)
mb.Insert(ipldfree.String("f1"), plz(_String__NodeBuilder{}.CreateString("a")))
mb.Insert(ipldfree.String("f2"), plz(_String__NodeBuilder{}.CreateString("b")))
mb.Insert(ipldfree.String("f3"), plz(_String__NodeBuilder{}.CreateString("c")))
mb.Insert(ipldfree.String("f4"), plz(_String__NodeBuilder{}.CreateString("d")))
mb.Insert(ipldfree.String("f1"), plz(String__NodeBuilder().CreateString("a")))
mb.Insert(ipldfree.String("f2"), plz(String__NodeBuilder().CreateString("b")))
mb.Insert(ipldfree.String("f3"), plz(String__NodeBuilder().CreateString("c")))
mb.Insert(ipldfree.String("f4"), plz(String__NodeBuilder().CreateString("d")))
n, err := mb.Build()
v0 = n.(typed.Node)
Wish(t, err, ShouldEqual, nil)
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("c")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("d")))
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(String__NodeBuilder().CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(String__NodeBuilder().CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(String__NodeBuilder().CreateString("c")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(String__NodeBuilder().CreateString("d")))
})
t.Run("using null nullable", func(t *testing.T) {
mb, err := _Stroct__NodeBuilder{}.CreateMap()
mb, err := Stroct__NodeBuilder().CreateMap()
Require(t, err, ShouldEqual, nil)
mb.Insert(ipldfree.String("f1"), plz(_String__NodeBuilder{}.CreateString("a")))
mb.Insert(ipldfree.String("f2"), plz(_String__NodeBuilder{}.CreateString("b")))
mb.Insert(ipldfree.String("f3"), plz(_String__NodeBuilder{}.CreateString("c")))
mb.Insert(ipldfree.String("f1"), plz(String__NodeBuilder().CreateString("a")))
mb.Insert(ipldfree.String("f2"), plz(String__NodeBuilder().CreateString("b")))
mb.Insert(ipldfree.String("f3"), plz(String__NodeBuilder().CreateString("c")))
mb.Insert(ipldfree.String("f4"), ipld.Null)
n, err := mb.Build()
v1 = n.(typed.Node)
......@@ -95,62 +95,62 @@ func TestGeneratedStructs(t *testing.T) {
Wish(t, err, ShouldEqual, nil)
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 4)
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("c")))
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(String__NodeBuilder().CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(String__NodeBuilder().CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(String__NodeBuilder().CreateString("c")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, ipld.Null)
})
t.Run("using null optional nullable", func(t *testing.T) {
mb, err := _Stroct__NodeBuilder{}.CreateMap()
mb, err := Stroct__NodeBuilder().CreateMap()
Require(t, err, ShouldEqual, nil)
mb.Insert(ipldfree.String("f1"), plz(_String__NodeBuilder{}.CreateString("a")))
mb.Insert(ipldfree.String("f2"), plz(_String__NodeBuilder{}.CreateString("b")))
mb.Insert(ipldfree.String("f1"), plz(String__NodeBuilder().CreateString("a")))
mb.Insert(ipldfree.String("f2"), plz(String__NodeBuilder().CreateString("b")))
mb.Insert(ipldfree.String("f3"), ipld.Null)
mb.Insert(ipldfree.String("f4"), plz(_String__NodeBuilder{}.CreateString("d")))
mb.Insert(ipldfree.String("f4"), plz(String__NodeBuilder().CreateString("d")))
n, err := mb.Build()
v2 = n.(typed.Node)
Wish(t, err, ShouldEqual, nil)
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 4)
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("b")))
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(String__NodeBuilder().CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(String__NodeBuilder().CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, ipld.Null)
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("d")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(String__NodeBuilder().CreateString("d")))
})
t.Run("using skipped optional", func(t *testing.T) {
mb, err := _Stroct__NodeBuilder{}.CreateMap()
mb, err := Stroct__NodeBuilder().CreateMap()
Require(t, err, ShouldEqual, nil)
mb.Insert(ipldfree.String("f1"), plz(_String__NodeBuilder{}.CreateString("a")))
mb.Insert(ipldfree.String("f3"), plz(_String__NodeBuilder{}.CreateString("c")))
mb.Insert(ipldfree.String("f4"), plz(_String__NodeBuilder{}.CreateString("d")))
mb.Insert(ipldfree.String("f1"), plz(String__NodeBuilder().CreateString("a")))
mb.Insert(ipldfree.String("f3"), plz(String__NodeBuilder().CreateString("c")))
mb.Insert(ipldfree.String("f4"), plz(String__NodeBuilder().CreateString("d")))
n, err := mb.Build()
v3 = n.(typed.Node)
Wish(t, err, ShouldEqual, nil)
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 4)
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("a")))
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(String__NodeBuilder().CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, ipld.Undef)
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("c")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("d")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(String__NodeBuilder().CreateString("c")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(String__NodeBuilder().CreateString("d")))
})
t.Run("using skipped optional nullable", func(t *testing.T) {
mb, err := _Stroct__NodeBuilder{}.CreateMap()
mb, err := Stroct__NodeBuilder().CreateMap()
Require(t, err, ShouldEqual, nil)
mb.Insert(ipldfree.String("f1"), plz(_String__NodeBuilder{}.CreateString("a")))
mb.Insert(ipldfree.String("f2"), plz(_String__NodeBuilder{}.CreateString("b")))
mb.Insert(ipldfree.String("f4"), plz(_String__NodeBuilder{}.CreateString("d")))
mb.Insert(ipldfree.String("f1"), plz(String__NodeBuilder().CreateString("a")))
mb.Insert(ipldfree.String("f2"), plz(String__NodeBuilder().CreateString("b")))
mb.Insert(ipldfree.String("f4"), plz(String__NodeBuilder().CreateString("d")))
n, err := mb.Build()
v4 = n.(typed.Node)
Wish(t, err, ShouldEqual, nil)
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 4)
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("b")))
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(String__NodeBuilder().CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(String__NodeBuilder().CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, ipld.Undef)
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("d")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(String__NodeBuilder().CreateString("d")))
})
})
t.Run("representation read", func(t *testing.T) {
......@@ -159,19 +159,19 @@ func TestGeneratedStructs(t *testing.T) {
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 4)
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("c")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("d")))
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(String__NodeBuilder().CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(String__NodeBuilder().CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(String__NodeBuilder().CreateString("c")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(String__NodeBuilder().CreateString("d")))
})
t.Run("using null nullable", func(t *testing.T) {
n := v1.Representation()
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 4)
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("c")))
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(String__NodeBuilder().CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(String__NodeBuilder().CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(String__NodeBuilder().CreateString("c")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, ipld.Null)
})
t.Run("using null optional nullable", func(t *testing.T) {
......@@ -179,30 +179,30 @@ func TestGeneratedStructs(t *testing.T) {
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 4)
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("b")))
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(String__NodeBuilder().CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(String__NodeBuilder().CreateString("b")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, ipld.Null)
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("d")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(String__NodeBuilder().CreateString("d")))
})
t.Run("using skipped optional", func(t *testing.T) {
n := v3.Representation()
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 3) // note this is shorter, even though it's not at the type level!
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("a")))
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(String__NodeBuilder().CreateString("a")))
Wish(t, erp(n.LookupString("f2")), ShouldEqual, ipld.ErrNotExists{ipld.PathSegmentOfString("f2")})
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("c")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("d")))
Wish(t, plz(n.LookupString("f3")), ShouldEqual, plz(String__NodeBuilder().CreateString("c")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(String__NodeBuilder().CreateString("d")))
})
t.Run("using skipped optional nullable", func(t *testing.T) {
n := v4.Representation()
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 3) // note this is shorter, even though it's not at the type level!
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("b")))
Wish(t, plz(n.LookupString("f1")), ShouldEqual, plz(String__NodeBuilder().CreateString("a")))
Wish(t, plz(n.LookupString("f2")), ShouldEqual, plz(String__NodeBuilder().CreateString("b")))
Wish(t, erp(n.LookupString("f3")), ShouldEqual, ipld.ErrNotExists{ipld.PathSegmentOfString("f3")})
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(_String__NodeBuilder{}.CreateString("d")))
Wish(t, plz(n.LookupString("f4")), ShouldEqual, plz(String__NodeBuilder().CreateString("d")))
})
// TODO will need even more cases to probe implicits
})
......@@ -237,7 +237,7 @@ func TestStructUnmarshal(t *testing.T) {
{Type: tok.TString, Str: "f4"}, {Type: tok.TString, Str: "d"},
{Type: tok.TMapClose},
}}
nb := _Stroct__NodeBuilder{}
nb := Stroct__NodeBuilder()
n, err := encoding.Unmarshal(nb, tb)
// ... asserts ...
})
......
......@@ -71,6 +71,7 @@ type nodeGenerator interface {
type nodebuilderGenerator interface {
EmitNodebuilderType(io.Writer)
EmitNodebuilderConstructor(io.Writer)
EmitNodebuilderMethodCreateMap(io.Writer)
EmitNodebuilderMethodAmendMap(io.Writer)
......
......@@ -35,6 +35,14 @@ func (gk generateNbKindString) EmitNodebuilderType(w io.Writer) {
`, w, gk)
}
func (gk generateNbKindString) EmitNodebuilderConstructor(w io.Writer) {
doTemplate(`
func {{ .Type | mungeNodebuilderConstructorIdent }}() ipld.NodeBuilder {
return {{ .Type | mungeTypeNodebuilderIdent }}{}
}
`, w, gk)
}
func (gk generateNbKindString) EmitNodebuilderMethodCreateString(w io.Writer) {
doTemplate(`
func (nb {{ .Type | mungeTypeNodebuilderIdent }}) CreateString(v string) (ipld.Node, error) {
......
......@@ -36,6 +36,14 @@ func (gk generateNbKindStruct) EmitNodebuilderType(w io.Writer) {
`, w, gk)
}
func (gk generateNbKindStruct) EmitNodebuilderConstructor(w io.Writer) {
doTemplate(`
func {{ .Type | mungeNodebuilderConstructorIdent }}() ipld.NodeBuilder {
return {{ .Type | mungeTypeNodebuilderIdent }}{}
}
`, w, gk)
}
func (gk generateNbKindStruct) EmitNodebuilderMethodCreateMap(w io.Writer) {
// Some interesting edge cases to note:
// - This builder, being all about semantics and not at all about serialization,
......
......@@ -208,6 +208,14 @@ func (gk generateStructReprMapNb) EmitNodebuilderType(w io.Writer) {
`, w, gk)
}
func (gk generateStructReprMapNb) EmitNodebuilderConstructor(w io.Writer) {
doTemplate(`
func {{ .Type | mungeReprNodebuilderConstructorIdent }}() ipld.NodeBuilder {
return {{ .Type | mungeTypeReprNodebuilderIdent }}{}
}
`, w, gk)
}
func (gk generateStructReprMapNb) EmitNodebuilderMethodCreateMap(w io.Writer) {
// Much of these looks the same as the type-level builders. Key differences:
// - We interact with the rename directives here.
......
......@@ -41,6 +41,7 @@ func TestNuevo(t *testing.T) {
tg.EmitNodeMethodNodeBuilder(w)
tnbg := tg.GetNodeBuilderGen()
tnbg.EmitNodebuilderType(w)
tnbg.EmitNodebuilderConstructor(w)
tnbg.EmitNodebuilderMethodCreateMap(w)
tnbg.EmitNodebuilderMethodAmendMap(w)
tnbg.EmitNodebuilderMethodCreateList(w)
......@@ -79,6 +80,7 @@ func TestNuevo(t *testing.T) {
rng.EmitNodeMethodNodeBuilder(w)
rnbg := rng.GetNodeBuilderGen()
rnbg.EmitNodebuilderType(w)
rnbg.EmitNodebuilderConstructor(w)
rnbg.EmitNodebuilderMethodCreateMap(w)
rnbg.EmitNodebuilderMethodAmendMap(w)
rnbg.EmitNodebuilderMethodCreateList(w)
......
......@@ -46,3 +46,11 @@ func mungeTypeReprNodeMapBuilderIdent(t schema.Type) string {
func mungeTypeReprNodeListBuilderIdent(t schema.Type) string {
return "_" + string(t.Name()) + "__ReprListBuilder"
}
func mungeNodebuilderConstructorIdent(t schema.Type) string {
return string(t.Name()) + "__NodeBuilder"
}
func mungeReprNodebuilderConstructorIdent(t schema.Type) string {
return string(t.Name()) + "__ReprNodeBuilder"
}
......@@ -32,6 +32,9 @@ func doTemplate(tmplstr string, w io.Writer, data interface{}) {
"mungeTypeReprNodebuilderIdent": mungeTypeReprNodebuilderIdent,
"mungeTypeReprNodeMapBuilderIdent": mungeTypeReprNodeMapBuilderIdent,
"mungeTypeReprNodeListBuilderIdent": mungeTypeReprNodeListBuilderIdent,
"mungeNodebuilderConstructorIdent": mungeNodebuilderConstructorIdent,
"mungeReprNodebuilderConstructorIdent": mungeReprNodebuilderConstructorIdent,
}).
Parse(wish.Dedent(tmplstr)))
if err := tmpl.Execute(w, data); err != 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