From 4da73fb9b8f6de175eff6a70c12ab7ad7ce4a534 Mon Sep 17 00:00:00 2001 From: Eric Myhre Date: Sun, 3 Jan 2021 18:42:01 +0100 Subject: [PATCH 1/2] gengo: support for unions with stringprefix representation. --- node/mixins/delim.go | 7 + schema/gen/go/README.md | 135 +++++----- schema/gen/go/genUnion.go | 9 +- schema/gen/go/genUnionReprStringprefix.go | 258 +++++++++++++++++++ schema/gen/go/generate.go | 2 + schema/gen/go/testUnionsStringprefix_test.go | 99 +++++++ schema/tmpBuilders.go | 3 + schema/type.go | 13 +- schema/typeMethods.go | 13 + 9 files changed, 467 insertions(+), 72 deletions(-) create mode 100644 schema/gen/go/genUnionReprStringprefix.go create mode 100644 schema/gen/go/testUnionsStringprefix_test.go diff --git a/node/mixins/delim.go b/node/mixins/delim.go index ed65d82a..e5f5a472 100644 --- a/node/mixins/delim.go +++ b/node/mixins/delim.go @@ -31,3 +31,10 @@ func SplitExact(s string, sep string, count int) ([]string, error) { } return ss, nil } + +// SplitN is an alias of strings.SplitN, which is only present here to +// make it usable in codegen packages without requiring conditional imports +// in the generation process. +func SplitN(s, sep string, n int) []string { + return strings.SplitN(s, sep, n) +} diff --git a/schema/gen/go/README.md b/schema/gen/go/README.md index 2e16748e..9dfb316c 100644 --- a/schema/gen/go/README.md +++ b/schema/gen/go/README.md @@ -47,70 +47,71 @@ Legend: - `?` - feature definition needed! (applies to many of the "native extras" rows -- often there's partial features, but also room for more.) - ` ` - table is not finished, please refer to the code and help fix the table :) -| feature | accessors | builders | -|:-------------------------------|:---------:|:--------:| -| structs | ... | ... | -| ... type level | ✔ | ✔ | -| ... native extras | ? | ? | -| ... map representation | ✔ | ✔ | -| ... ... including optional | ✔ | ✔ | -| ... ... including renames | ✔ | ✔ | -| ... ... including implicits | ⚠ | ⚠ | -| ... tuple representation | ✔ | ✔ | -| ... ... including optional | ✔ | ✔ | -| ... ... including renames | - | - | -| ... ... including implicits | ⚠ | ⚠ | -| ... stringjoin representation | ✔ | ✔ | -| ... ... including optional | - | - | -| ... ... including renames | - | - | -| ... ... including implicits | - | - | -| ... stringpairs representation | ✘ | ✘ | -| ... ... including optional | | | -| ... ... including renames | | | -| ... ... including implicits | | | -| ... listpairs representation | ✘ | ✘ | -| ... ... including optional | | | -| ... ... including renames | | | -| ... ... including implicits | | | - -| feature | accessors | builders | -|:-------------------------------|:---------:|:--------:| -| lists | ... | ... | -| ... type level | ✔ | ✔ | -| ... native extras | ? | ? | -| ... list representation | ✔ | ✔ | - -| feature | accessors | builders | -|:-------------------------------|:---------:|:--------:| -| maps | ... | ... | -| ... type level | ✔ | ✔ | -| ... native extras | ? | ? | -| ... map representation | ✔ | ✔ | -| ... stringpairs representation | ✘ | ✘ | -| ... listpairs representation | ✘ | ✘ | - -| feature | accessors | builders | -|:-------------------------------|:---------:|:--------:| -| unions | ... | ... | -| ... type level | ✔ | ✔ | -| ... keyed representation | ✔ | ✔ | -| ... envelope representation | ✘ | ✘ | -| ... kinded representation | ✔ | ✔ | -| ... inline representation | ✘ | ✘ | -| ... byteprefix representation | ✘ | ✘ | - -| feature | accessors | builders | -|:-------------------------------|:---------:|:--------:| -| strings | ✔ | ✔ | -| bytes | ✔ | ✔ | -| ints | ✔ | ✔ | -| floats | ✔ | ✔ | -| bools | ✔ | ✔ | -| links | ✔ | ✔ | - -| feature | accessors | builders | -|:-------------------------------|:---------:|:--------:| -| enums | ... | ... | -| ... type level | ✘ | ✘ | -| ... string representation | ✘ | ✘ | -| ... int representation | ✘ | ✘ | +| feature | accessors | builders | +|:---------------------------------|:---------:|:--------:| +| structs | ... | ... | +| ... type level | ✔ | ✔ | +| ... native extras | ? | ? | +| ... map representation | ✔ | ✔ | +| ... ... including optional | ✔ | ✔ | +| ... ... including renames | ✔ | ✔ | +| ... ... including implicits | ⚠ | ⚠ | +| ... tuple representation | ✔ | ✔ | +| ... ... including optional | ✔ | ✔ | +| ... ... including renames | - | - | +| ... ... including implicits | ⚠ | ⚠ | +| ... stringjoin representation | ✔ | ✔ | +| ... ... including optional | - | - | +| ... ... including renames | - | - | +| ... ... including implicits | - | - | +| ... stringpairs representation | ✘ | ✘ | +| ... ... including optional | | | +| ... ... including renames | | | +| ... ... including implicits | | | +| ... listpairs representation | ✘ | ✘ | +| ... ... including optional | | | +| ... ... including renames | | | +| ... ... including implicits | | | + +| feature | accessors | builders | +|:---------------------------------|:---------:|:--------:| +| lists | ... | ... | +| ... type level | ✔ | ✔ | +| ... native extras | ? | ? | +| ... list representation | ✔ | ✔ | + +| feature | accessors | builders | +|:---------------------------------|:---------:|:--------:| +| maps | ... | ... | +| ... type level | ✔ | ✔ | +| ... native extras | ? | ? | +| ... map representation | ✔ | ✔ | +| ... stringpairs representation | ✘ | ✘ | +| ... listpairs representation | ✘ | ✘ | + +| feature | accessors | builders | +|:---------------------------------|:---------:|:--------:| +| unions | ... | ... | +| ... type level | ✔ | ✔ | +| ... keyed representation | ✔ | ✔ | +| ... envelope representation | ✘ | ✘ | +| ... kinded representation | ✔ | ✔ | +| ... inline representation | ✘ | ✘ | +| ... stringprefix representation | ✔ | ✔ | +| ... byteprefix representation | ✘ | ✘ | + +| feature | accessors | builders | +|:---------------------------------|:---------:|:--------:| +| strings | ✔ | ✔ | +| bytes | ✔ | ✔ | +| ints | ✔ | ✔ | +| floats | ✔ | ✔ | +| bools | ✔ | ✔ | +| links | ✔ | ✔ | + +| feature | accessors | builders | +|:---------------------------------|:---------:|:--------:| +| enums | ... | ... | +| ... type level | ✘ | ✘ | +| ... string representation | ✘ | ✘ | +| ... int representation | ✘ | ✘ | diff --git a/schema/gen/go/genUnion.go b/schema/gen/go/genUnion.go index ca04c193..d8b2189d 100644 --- a/schema/gen/go/genUnion.go +++ b/schema/gen/go/genUnion.go @@ -40,13 +40,17 @@ func (g unionGenerator) EmitNativeType(w io.Writer) { // // The interface *mostly* isn't used... except for in the return type of a speciated function which can be used to do golang-native type switches. // + // The interface also includes a requirement for an errorless primitive access method (such as `String() string`) + // if our representation strategy is one that has that semantic (e.g., stringprefix repr does). + // // A note about index: in all cases the index of a member type is used, we increment it by one, to avoid using zero. // We do this because it's desirable to reserve the zero in the 'tag' field (if we generate one) as a sentinel value // (see further comments in the EmitNodeAssemblerType function); // and since we do it in that one case, it's just as well to do it uniformly. doTemplate(` {{- if Comments -}} - // {{ .Type | TypeSymbol }} matches the IPLD Schema type "{{ .Type.Name }}". It has {{ .Type.TypeKind }} type-kind, and may be interrogated like {{ .Kind }} kind. + // {{ .Type | TypeSymbol }} matches the IPLD Schema type "{{ .Type.Name }}". + // {{ .Type | TypeSymbol }} has {{ .Type.TypeKind }} typekind, which means its data model behaviors are that of a {{ .Kind }} kind. {{- end}} type {{ .Type | TypeSymbol }} = *_{{ .Type | TypeSymbol }} type _{{ .Type | TypeSymbol }} struct { @@ -61,6 +65,9 @@ func (g unionGenerator) EmitNativeType(w io.Writer) { } type _{{ .Type | TypeSymbol }}__iface interface { _{{ .Type | TypeSymbol }}__member() + {{- if (eq (.Type.RepresentationStrategy | printf "%T") "schema.UnionRepresentation_Stringprefix") }} + String() string + {{- end}} } {{- range $member := .Type.Members }} diff --git a/schema/gen/go/genUnionReprStringprefix.go b/schema/gen/go/genUnionReprStringprefix.go new file mode 100644 index 00000000..21d312cd --- /dev/null +++ b/schema/gen/go/genUnionReprStringprefix.go @@ -0,0 +1,258 @@ +package gengo + +import ( + "io" + + "github.com/ipld/go-ipld-prime/schema" + "github.com/ipld/go-ipld-prime/schema/gen/go/mixins" +) + +var _ TypeGenerator = &unionReprStringprefixGenerator{} + +func NewUnionReprStringprefixGenerator(pkgName string, typ *schema.TypeUnion, adjCfg *AdjunctCfg) TypeGenerator { + return unionReprStringprefixGenerator{ + unionGenerator{ + adjCfg, + mixins.MapTraits{ + PkgName: pkgName, + TypeName: string(typ.Name()), + TypeSymbol: adjCfg.TypeSymbol(typ), + }, + pkgName, + typ, + }, + } +} + +type unionReprStringprefixGenerator struct { + unionGenerator +} + +func (g unionReprStringprefixGenerator) GetRepresentationNodeGen() NodeGenerator { + return unionReprStringprefixReprGenerator{ + g.AdjCfg, + mixins.StringTraits{ + PkgName: g.PkgName, + TypeName: string(g.Type.Name()) + ".Repr", + TypeSymbol: "_" + g.AdjCfg.TypeSymbol(g.Type) + "__Repr", + }, + g.PkgName, + g.Type, + } +} + +type unionReprStringprefixReprGenerator struct { + AdjCfg *AdjunctCfg + mixins.StringTraits + PkgName string + Type *schema.TypeUnion +} + +func (unionReprStringprefixReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates. + +func (g unionReprStringprefixReprGenerator) EmitNodeType(w io.Writer) { + // The type is structurally the same, but will have a different set of methods. + doTemplate(` + type _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }} + `, w, g.AdjCfg, g) + + // We do also want some constants for our discriminant values; + // they'll make iterators able to work faster. + doTemplate(` + var ( + {{- range $member := .Type.Members }} + memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial = _String{"{{ $member | dot.Type.RepresentationStrategy.GetDiscriminant }}"} + {{- end }} + ) + `, w, g.AdjCfg, g) +} + +func (g unionReprStringprefixReprGenerator) EmitNodeTypeAssertions(w io.Writer) { + doTemplate(` + var _ ipld.Node = &_{{ .Type | TypeSymbol }}__Repr{} + `, w, g.AdjCfg, g) +} + +func (g unionReprStringprefixReprGenerator) EmitNodeMethodAsString(w io.Writer) { + // See comment block in structReprStringjoinReprGenerator.EmitNodeMethodAsString for a lot of philosophizing about this. + doTemplate(` + func (n *_{{ .Type | TypeSymbol }}__Repr) AsString() (string, error) { + return n.String(), nil + } + func (n *_{{ .Type | TypeSymbol }}__Repr) String() string { + {{- if (eq (.AdjCfg.UnionMemlayout .Type) "embedAll") }} + switch n.tag { + {{- range $i, $member := .Type.Members }} + case {{ add $i 1 }}: + return memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial.String() + "{{ dot.Type.RepresentationStrategy.GetDelim }}" + n.x{{ add $i 1 }}.String() + {{- end}} + {{- else if (eq (.AdjCfg.UnionMemlayout .Type) "interface") }} + switch n2 := n.x.(type) { + {{- range $member := .Type.Members }} + case {{ $member | TypeSymbol }}: + return memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial.String() + "{{ dot.Type.RepresentationStrategy.GetDelim }}" + n2.String() + {{- end}} + {{- end}} + default: + panic("unreachable") + } + } + func (n {{ .Type | TypeSymbol }}) String() string { + return (*_{{ .Type | TypeSymbol }}__Repr)(n).String() + } + `, w, g.AdjCfg, g) +} + +func (g unionReprStringprefixReprGenerator) EmitNodeMethodPrototype(w io.Writer) { + emitNodeMethodPrototype_typical(w, g.AdjCfg, g) +} + +func (g unionReprStringprefixReprGenerator) EmitNodePrototypeType(w io.Writer) { + emitNodePrototypeType_typical(w, g.AdjCfg, g) +} + +// --- NodeBuilder and NodeAssembler ---> + +func (g unionReprStringprefixReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator { + return unionReprStringprefixReprBuilderGenerator{ + g.AdjCfg, + mixins.StringAssemblerTraits{ + PkgName: g.PkgName, + TypeName: g.TypeName, + AppliedPrefix: "_" + g.AdjCfg.TypeSymbol(g.Type) + "__Repr", + }, + g.PkgName, + g.Type, + } +} + +type unionReprStringprefixReprBuilderGenerator struct { + AdjCfg *AdjunctCfg + mixins.StringAssemblerTraits + PkgName string + Type *schema.TypeUnion +} + +func (unionReprStringprefixReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates. + +func (g unionReprStringprefixReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) { + emitEmitNodeBuilderType_typical(w, g.AdjCfg, g) +} +func (g unionReprStringprefixReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) { + emitNodeBuilderMethods_typical(w, g.AdjCfg, g) + + // Generate a single-step construction function -- this is easy to do for a scalar, + // and all representations of scalar kind can be expected to have a method like this. + // The function is attached to the NodePrototype for convenient namespacing; + // it needs no new memory, so it would be inappropriate to attach to the builder or assembler. + // The function is directly used internally by anything else that might involve recursive destructuring on the same scalar kind + // (for example, structs using stringjoin strategies that have one of this type as a field, etc). + // Since we're a representation of scalar kind, and can recurse, + // we ourselves presume this plain construction method must also exist for all our members. + // REVIEW: We could make an immut-safe verion of this and export it on the NodePrototype too, as `FromString(string)`. + doTemplate(` + func (_{{ .Type | TypeSymbol }}__ReprPrototype) fromString(w *_{{ .Type | TypeSymbol }}, v string) error { + ss := mixins.SplitN(v, "{{ .Type.RepresentationStrategy.GetDelim }}", 2) + if len(ss) != 2 { + return ipld.ErrUnmatchable{TypeName:"{{ .PkgName }}.{{ .Type.Name }}.Repr"}.Reasonf("expecting a stringprefix union but found no delimiter in the value") + } + switch ss[0] { + {{- range $i, $member := .Type.Members }} + case "{{ $member | dot.Type.RepresentationStrategy.GetDiscriminant }}": + {{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) "embedAll") }} + w.tag = {{ add $i 1 }} + if err := (_{{ $member | TypeSymbol }}__ReprPrototype{}).fromString(&w.x{{ add $i 1 }}, ss[1]); err != nil { + return ipld.ErrUnmatchable{TypeName:"{{ dot.PkgName }}.{{ dot.Type.Name }}.Repr", Reason: err} + } + return nil + {{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) "interface") }} + var n2 _{{ $member | TypeSymbol }} + if err := (_{{ $member | TypeSymbol }}__ReprPrototype{}).fromString(&n2, ss[1]); err != nil { + return ipld.ErrUnmatchable{TypeName:"{{ dot.PkgName }}.{{ dot.Type.Name }}.Repr", Reason: err} + } + w.x = &n2 + return nil + {{- end}} + {{- end}} + default: + return schema.ErrNoSuchField{Type: nil /*TODO*/, Field: ipld.PathSegmentOfString(ss[0])} + } + } + `, w, g.AdjCfg, g) +} +func (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) { + doTemplate(` + type _{{ .Type | TypeSymbol }}__ReprAssembler struct { + w *_{{ .Type | TypeSymbol }} + m *schema.Maybe + } + + func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {} + `, w, g.AdjCfg, g) +} +func (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) { + emitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g) +} +func (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(w io.Writer) { + // This method contains a branch to support MaybeUsesPtr because new memory may need to be allocated. + // This allocation only happens if the 'w' ptr is nil, which means we're being used on a Maybe; + // otherwise, the 'w' ptr should already be set, and we fill that memory location without allocating, as usual. + // TODO:DRY: this is identical to other string-repr-on-non-string-type. + doTemplate(` + func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignString(v string) error { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + {{- if .Type | MaybeUsesPtr }} + if na.w == nil { + na.w = &_{{ .Type | TypeSymbol }}{} + } + {{- end}} + if err := (_{{ .Type | TypeSymbol }}__ReprPrototype{}).fromString(na.w, v); err != nil { + return err + } + *na.m = schema.Maybe_Value + return nil + } + `, w, g.AdjCfg, g) +} + +func (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) { + // AssignNode goes through three phases: + // 1. is it null? Jump over to AssignNull (which may or may not reject it). + // 2. is it our own type? Handle specially -- we might be able to do efficient things. + // 3. is it the right kind to morph into us? Do so. + // TODO:DRY: this is identical to other string-repr-on-non-string-type. + doTemplate(` + func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignNode(v ipld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + {{- if .Type | MaybeUsesPtr }} + if na.w == nil { + na.w = v2 + *na.m = schema.Maybe_Value + return nil + } + {{- end}} + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v2, err := v.AsString(); err != nil { + return err + } else { + return na.AssignString(v2) + } + } + `, w, g.AdjCfg, g) +} +func (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) { + // None for this. +} diff --git a/schema/gen/go/generate.go b/schema/gen/go/generate.go index bd15a6cb..ef9ca571 100644 --- a/schema/gen/go/generate.go +++ b/schema/gen/go/generate.go @@ -74,6 +74,8 @@ func Generate(pth string, pkgName string, ts schema.TypeSystem, adjCfg *AdjunctC fn(NewUnionReprKeyedGenerator(pkgName, t2, adjCfg), f) case schema.UnionRepresentation_Kinded: fn(NewUnionReprKindedGenerator(pkgName, t2, adjCfg), f) + case schema.UnionRepresentation_Stringprefix: + fn(NewUnionReprStringprefixGenerator(pkgName, t2, adjCfg), f) default: panic("unrecognized union representation strategy") } diff --git a/schema/gen/go/testUnionsStringprefix_test.go b/schema/gen/go/testUnionsStringprefix_test.go new file mode 100644 index 00000000..5decb716 --- /dev/null +++ b/schema/gen/go/testUnionsStringprefix_test.go @@ -0,0 +1,99 @@ +package gengo + +import ( + "testing" + + "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/schema" +) + +func TestUnionStringprefix(t *testing.T) { + t.Parallel() + + ts := schema.TypeSystem{} + ts.Init() + adjCfg := &AdjunctCfg{} + ts.Accumulate(schema.SpawnString("String")) + ts.Accumulate(schema.SpawnStruct("SmolStruct", + []schema.StructField{ + schema.SpawnStructField("a", "String", false, false), + schema.SpawnStructField("b", "String", false, false), + }, + schema.SpawnStructRepresentationStringjoin(":"), + )) + ts.Accumulate(schema.SpawnUnion("WheeUnion", + []schema.TypeName{ + "String", + "SmolStruct", + }, + schema.SpawnUnionRepresentationStringprefix( + ":", + map[string]schema.TypeName{ + "simple": "String", + "complex": "SmolStruct", + }, + ), + )) + + // These are the same *type-level* as in TestUnionKeyedComplexChildren, + // but (of course) have very different representations. + specs := []testcase{ + { + name: "InhabitantA", + typeJson: `{"String":"whee"}`, + reprJson: `"simple:whee"`, + typePoints: []testcasePoint{ + {"", ipld.Kind_Map}, + {"String", "whee"}, + //{"SmolStruct", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package. + }, + reprPoints: []testcasePoint{ + {"", ipld.Kind_String}, + {"", "simple:whee"}, + }, + }, + { + name: "InhabitantB", + typeJson: `{"SmolStruct":{"a":"whee","b":"woo"}}`, + reprJson: `"complex:whee:woo"`, + typePoints: []testcasePoint{ + {"", ipld.Kind_Map}, + //{"String", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package. + {"SmolStruct", ipld.Kind_Map}, + {"SmolStruct/a", "whee"}, + {"SmolStruct/b", "woo"}, + }, + reprPoints: []testcasePoint{ + {"", ipld.Kind_String}, + {"", "complex:whee:woo"}, + }, + }, + } + + test := func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) { + np := getPrototypeByName("WheeUnion") + nrp := getPrototypeByName("WheeUnion.Repr") + for _, tcase := range specs { + tcase.Test(t, np, nrp) + } + } + + t.Run("union-using-embed", func(t *testing.T) { + adjCfg.CfgUnionMemlayout = map[schema.TypeName]string{"WheeUnion": "embedAll"} + + prefix := "union-stringprefix-using-embed" + pkgName := "main" + genAndCompileAndTest(t, prefix, pkgName, ts, adjCfg, func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) { + test(t, getPrototypeByName) + }) + }) + t.Run("union-using-interface", func(t *testing.T) { + adjCfg.CfgUnionMemlayout = map[schema.TypeName]string{"WheeUnion": "interface"} + + prefix := "union-stringprefix-using-interface" + pkgName := "main" + genAndCompileAndTest(t, prefix, pkgName, ts, adjCfg, func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) { + test(t, getPrototypeByName) + }) + }) +} diff --git a/schema/tmpBuilders.go b/schema/tmpBuilders.go index 690a7a2a..c1be779e 100644 --- a/schema/tmpBuilders.go +++ b/schema/tmpBuilders.go @@ -107,6 +107,9 @@ func SpawnUnionRepresentationKeyed(table map[string]TypeName) UnionRepresentatio func SpawnUnionRepresentationKinded(table map[ipld.Kind]TypeName) UnionRepresentation_Kinded { return UnionRepresentation_Kinded{table} } +func SpawnUnionRepresentationStringprefix(delim string, table map[string]TypeName) UnionRepresentation_Stringprefix { + return UnionRepresentation_Stringprefix{delim, table} +} // The methods relating to TypeSystem are also mutation-heavy and placeholdery. diff --git a/schema/type.go b/schema/type.go index c776bef2..f2565e8a 100644 --- a/schema/type.go +++ b/schema/type.go @@ -165,10 +165,11 @@ type TypeUnion struct { type UnionRepresentation interface{ _UnionRepresentation() } -func (UnionRepresentation_Keyed) _UnionRepresentation() {} -func (UnionRepresentation_Kinded) _UnionRepresentation() {} -func (UnionRepresentation_Envelope) _UnionRepresentation() {} -func (UnionRepresentation_Inline) _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); @@ -190,6 +191,10 @@ 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 diff --git a/schema/typeMethods.go b/schema/typeMethods.go index 300c9195..73d5aa10 100644 --- a/schema/typeMethods.go +++ b/schema/typeMethods.go @@ -148,6 +148,19 @@ func (r UnionRepresentation_Keyed) GetDiscriminant(t Type) string { 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 ipld.Kind) TypeName { From bc66b1e3e4bfa7fd38723b5fe1b3ff2b750e2f87 Mon Sep 17 00:00:00 2001 From: Eric Myhre Date: Thu, 7 Jan 2021 20:38:30 +0100 Subject: [PATCH 2/2] Use more explicit field names in initializers. --- schema/gen/go/genUnionReprStringprefix.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/schema/gen/go/genUnionReprStringprefix.go b/schema/gen/go/genUnionReprStringprefix.go index 21d312cd..53fbe664 100644 --- a/schema/gen/go/genUnionReprStringprefix.go +++ b/schema/gen/go/genUnionReprStringprefix.go @@ -12,14 +12,14 @@ var _ TypeGenerator = &unionReprStringprefixGenerator{} func NewUnionReprStringprefixGenerator(pkgName string, typ *schema.TypeUnion, adjCfg *AdjunctCfg) TypeGenerator { return unionReprStringprefixGenerator{ unionGenerator{ - adjCfg, - mixins.MapTraits{ + AdjCfg: adjCfg, + MapTraits: mixins.MapTraits{ PkgName: pkgName, TypeName: string(typ.Name()), TypeSymbol: adjCfg.TypeSymbol(typ), }, - pkgName, - typ, + PkgName: pkgName, + Type: typ, }, } } @@ -30,14 +30,14 @@ type unionReprStringprefixGenerator struct { func (g unionReprStringprefixGenerator) GetRepresentationNodeGen() NodeGenerator { return unionReprStringprefixReprGenerator{ - g.AdjCfg, - mixins.StringTraits{ + AdjCfg: g.AdjCfg, + StringTraits: mixins.StringTraits{ PkgName: g.PkgName, TypeName: string(g.Type.Name()) + ".Repr", TypeSymbol: "_" + g.AdjCfg.TypeSymbol(g.Type) + "__Repr", }, - g.PkgName, - g.Type, + PkgName: g.PkgName, + Type: g.Type, } }