github.com/ipld/go-ipld-prime@v0.21.0/schema/gen/go/genUnionReprKinded.go (about)

     1  package gengo
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/ipld/go-ipld-prime/schema"
     7  	"github.com/ipld/go-ipld-prime/schema/gen/go/mixins"
     8  )
     9  
    10  var _ TypeGenerator = &unionKindedGenerator{}
    11  
    12  // Kinded union representations are quite wild: their behavior varies almost completely per inhabitant,
    13  //  and their implementation is generally delegating directly to something else,
    14  //   rather than having an intermediate node (like most unions do, and like the type-level view of this same value will).
    15  //
    16  // This also means any error values can be a little weird:
    17  //  sometimes they'll have the union's type name, but sometimes they'll have the inhabitant's type name instead;
    18  //  this depends on whether the error is an ErrWrongKind that was found while checking the method for appropriateness on the union's inhabitant
    19  //  versus if the error came from the union inhabitant itself after delegation occured.
    20  
    21  func NewUnionReprKindedGenerator(pkgName string, typ *schema.TypeUnion, adjCfg *AdjunctCfg) TypeGenerator {
    22  	return unionKindedGenerator{
    23  		unionGenerator{
    24  			adjCfg,
    25  			mixins.MapTraits{
    26  				PkgName:    pkgName,
    27  				TypeName:   string(typ.Name()),
    28  				TypeSymbol: adjCfg.TypeSymbol(typ),
    29  			},
    30  			pkgName,
    31  			typ,
    32  		},
    33  	}
    34  }
    35  
    36  type unionKindedGenerator struct {
    37  	unionGenerator
    38  }
    39  
    40  func (g unionKindedGenerator) GetRepresentationNodeGen() NodeGenerator {
    41  	return unionKindedReprGenerator{
    42  		g.AdjCfg,
    43  		g.PkgName,
    44  		g.Type,
    45  	}
    46  }
    47  
    48  type unionKindedReprGenerator struct {
    49  	// Note that there's no MapTraits (or any other FooTraits) mixin in this one!
    50  	//  This is no accident: *None* of them apply!
    51  
    52  	AdjCfg  *AdjunctCfg
    53  	PkgName string
    54  	Type    *schema.TypeUnion
    55  }
    56  
    57  func (unionKindedReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates.
    58  
    59  func (g unionKindedReprGenerator) EmitNodeType(w io.Writer) {
    60  	// The type is structurally the same, but will have a different set of methods.
    61  	doTemplate(`
    62  		type _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }}
    63  	`, w, g.AdjCfg, g)
    64  }
    65  
    66  func (g unionKindedReprGenerator) EmitNodeTypeAssertions(w io.Writer) {
    67  	doTemplate(`
    68  		var _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}
    69  	`, w, g.AdjCfg, g)
    70  }
    71  
    72  func (g unionKindedReprGenerator) EmitNodeMethodKind(w io.Writer) {
    73  	doTemplate(`
    74  		func (n *_{{ .Type | TypeSymbol }}__Repr) Kind() datamodel.Kind {
    75  			{{- if (eq (.AdjCfg.UnionMemlayout .Type) "embedAll") }}
    76  			switch n.tag {
    77  			{{- range $i, $member := .Type.Members }}
    78  			case {{ add $i 1 }}:
    79  				return {{ $member.RepresentationBehavior | KindSymbol }}
    80  			{{- end}}
    81  			{{- else if (eq (.AdjCfg.UnionMemlayout .Type) "interface") }}
    82  			switch n.x.(type) {
    83  			{{- range $i, $member := .Type.Members }}
    84  			case {{ $member | TypeSymbol }}:
    85  				return {{ $member.RepresentationBehavior | KindSymbol }}
    86  			{{- end}}
    87  			{{- end}}
    88  			default:
    89  				panic("unreachable")
    90  			}
    91  		}
    92  	`, w, g.AdjCfg, g)
    93  }
    94  
    95  func kindedUnionNodeMethodTemplateMunge(
    96  	methodName string, // for error messages
    97  	methodSig string, // output literally
    98  	someSwitchClause string, // template condition for if *any* switch clause should be present
    99  	condClause string, // template condition for the member this should match on when in the range
   100  	retClause string, // clause returning the thing (how to delegate methodsig, generally)
   101  	appropriateKind string, // for error messages
   102  	nopeSentinel string, // for error return paths; generally the zero value for the first return type.
   103  	nopeSentinelOnly bool, // true if this method has no error return, just the sentinel.
   104  ) string {
   105  	// We really could just... call the methods directly (and elide the switch entirely all the time), in the case of the "interface" implementation strategy.
   106  	//  We don't, though, because that would deprive us of getting the union type's name in the wrong-kind errors...
   107  	//   and in addition to that being sadface in general, it would be downright unacceptable if that behavior varied based on implementation strategy.
   108  	//
   109  	// This error text doesn't tell us what the member kind is.  This might read weirdly.
   110  	//  It's possible we could try to cram a description of the inhabitant into the "TypeName" since it's stringy; but unclear if that's a good idea either.
   111  
   112  	// These template concatenations have evolved into a mess very quickly.  This entire thing should be replaced.
   113  	//  String concatenations of template clauses is an atrociously unhygenic way to compose things;
   114  	//   it looked like we could limp by with it for a while, but it's gotten messier faster than expected.
   115  
   116  	errorClause := `return ` + nopeSentinel
   117  	if !nopeSentinelOnly {
   118  		errorClause += `, datamodel.ErrWrongKind{TypeName: "{{ .PkgName }}.{{ .Type.Name }}.Repr", MethodName: "` + methodName + `", AppropriateKind: ` + appropriateKind + `, ActualKind: n.Kind()}`
   119  	}
   120  	return `
   121  		func (n *_{{ .Type | TypeSymbol }}__Repr) ` + methodSig + ` {
   122  			` + someSwitchClause + `
   123  			{{- if (eq (.AdjCfg.UnionMemlayout .Type) "embedAll") }}
   124  			switch n.tag {
   125  			{{- range $i, $member := .Type.Members }}
   126  			` + condClause + `
   127  			case {{ add $i 1 }}:
   128  				return n.x{{ add $i 1 }}.Representation()` + retClause + `
   129  			{{- end}}
   130  			{{- end}}
   131  			{{- else if (eq (.AdjCfg.UnionMemlayout .Type) "interface") }}
   132  			switch n2 := n.x.(type) {
   133  			{{- range $i, $member := .Type.Members }}
   134  			` + condClause + `
   135  			case {{ $member | TypeSymbol }}:
   136  				return n2.Representation()` + retClause + `
   137  			{{- end}}
   138  			{{- end}}
   139  			{{- end}}
   140  			default:
   141  			{{- end}}
   142  				` + errorClause + `
   143  			` + someSwitchClause + `
   144  			}
   145  			{{- end}}
   146  		}
   147  	`
   148  }
   149  
   150  func (g unionKindedReprGenerator) EmitNodeMethodLookupByString(w io.Writer) {
   151  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   152  		`LookupByString`,
   153  		`LookupByString(key string) (datamodel.Node, error)`,
   154  		`{{- if .Type.RepresentationStrategy.GetMember (Kind "map") }}`,
   155  		`{{- if eq $member.RepresentationBehavior.String "map" }}`,
   156  		`.LookupByString(key)`,
   157  		`datamodel.KindSet_JustMap`,
   158  		`nil`,
   159  		false,
   160  	), w, g.AdjCfg, g)
   161  }
   162  
   163  func (g unionKindedReprGenerator) EmitNodeMethodLookupByIndex(w io.Writer) {
   164  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   165  		`LookupByIndex`,
   166  		`LookupByIndex(idx int64) (datamodel.Node, error)`,
   167  		`{{- if .Type.RepresentationStrategy.GetMember (Kind "list") }}`,
   168  		`{{- if eq $member.RepresentationBehavior.String "list" }}`,
   169  		`.LookupByIndex(idx)`,
   170  		`datamodel.KindSet_JustList`,
   171  		`nil`,
   172  		false,
   173  	), w, g.AdjCfg, g)
   174  }
   175  
   176  func (g unionKindedReprGenerator) EmitNodeMethodLookupByNode(w io.Writer) {
   177  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   178  		`LookupByNode`,
   179  		`LookupByNode(key datamodel.Node) (datamodel.Node, error)`,
   180  		`{{- if or (.Type.RepresentationStrategy.GetMember (Kind "map")) (.Type.RepresentationStrategy.GetMember (Kind "list")) }}`,
   181  		`{{- if or (eq $member.RepresentationBehavior.String "map") (eq $member.RepresentationBehavior.String "list") }}`,
   182  		`.LookupByNode(key)`,
   183  		`datamodel.KindSet_Recursive`,
   184  		`nil`,
   185  		false,
   186  	), w, g.AdjCfg, g)
   187  }
   188  
   189  func (g unionKindedReprGenerator) EmitNodeMethodLookupBySegment(w io.Writer) {
   190  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   191  		`LookupBySegment`,
   192  		`LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error)`,
   193  		`{{- if or (.Type.RepresentationStrategy.GetMember (Kind "map")) (.Type.RepresentationStrategy.GetMember (Kind "list")) }}`,
   194  		`{{- if or (eq $member.RepresentationBehavior.String "map") (eq $member.RepresentationBehavior.String "list") }}`,
   195  		`.LookupBySegment(seg)`,
   196  		`datamodel.KindSet_Recursive`,
   197  		`nil`,
   198  		false,
   199  	), w, g.AdjCfg, g)
   200  }
   201  
   202  func (g unionKindedReprGenerator) EmitNodeMethodMapIterator(w io.Writer) {
   203  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   204  		`MapIterator`,
   205  		`MapIterator() datamodel.MapIterator`,
   206  		`{{- if .Type.RepresentationStrategy.GetMember (Kind "map") }}`,
   207  		`{{- if eq $member.RepresentationBehavior.String "map" }}`,
   208  		`.MapIterator()`,
   209  		`datamodel.KindSet_JustMap`,
   210  		`nil`,
   211  		true,
   212  	), w, g.AdjCfg, g)
   213  }
   214  
   215  func (g unionKindedReprGenerator) EmitNodeMethodListIterator(w io.Writer) {
   216  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   217  		`ListIterator`,
   218  		`ListIterator() datamodel.ListIterator`,
   219  		`{{- if .Type.RepresentationStrategy.GetMember (Kind "list") }}`,
   220  		`{{- if eq $member.RepresentationBehavior.String "list" }}`,
   221  		`.ListIterator()`,
   222  		`datamodel.KindSet_JustList`,
   223  		`nil`,
   224  		true,
   225  	), w, g.AdjCfg, g)
   226  }
   227  
   228  func (g unionKindedReprGenerator) EmitNodeMethodLength(w io.Writer) {
   229  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   230  		`Length`,
   231  		`Length() int64`,
   232  		`{{- if or (.Type.RepresentationStrategy.GetMember (Kind "map")) (.Type.RepresentationStrategy.GetMember (Kind "list")) }}`,
   233  		`{{- if or (eq $member.RepresentationBehavior.String "map") (eq $member.RepresentationBehavior.String "list") }}`,
   234  		`.Length()`,
   235  		`datamodel.KindSet_Recursive`,
   236  		`-1`,
   237  		true,
   238  	), w, g.AdjCfg, g)
   239  }
   240  
   241  func (g unionKindedReprGenerator) EmitNodeMethodIsAbsent(w io.Writer) {
   242  	doTemplate(`
   243  		func (n *_{{ .Type | TypeSymbol }}__Repr) IsAbsent() bool {
   244  			return false
   245  		}
   246  	`, w, g.AdjCfg, g)
   247  }
   248  
   249  func (g unionKindedReprGenerator) EmitNodeMethodIsNull(w io.Writer) {
   250  	doTemplate(`
   251  		func (n *_{{ .Type | TypeSymbol }}__Repr) IsNull() bool {
   252  			return false
   253  		}
   254  	`, w, g.AdjCfg, g)
   255  }
   256  
   257  func (g unionKindedReprGenerator) EmitNodeMethodAsBool(w io.Writer) {
   258  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   259  		`AsBool`,
   260  		`AsBool() (bool, error)`,
   261  		`{{- if .Type.RepresentationStrategy.GetMember (Kind "bool") }}`,
   262  		`{{- if eq $member.RepresentationBehavior.String "bool" }}`,
   263  		`.AsBool()`,
   264  		`datamodel.KindSet_JustBool`,
   265  		`false`,
   266  		false,
   267  	), w, g.AdjCfg, g)
   268  }
   269  
   270  func (g unionKindedReprGenerator) EmitNodeMethodAsInt(w io.Writer) {
   271  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   272  		`AsInt`,
   273  		`AsInt() (int64, error)`,
   274  		`{{- if .Type.RepresentationStrategy.GetMember (Kind "int") }}`,
   275  		`{{- if eq $member.RepresentationBehavior.String "int" }}`,
   276  		`.AsInt()`,
   277  		`datamodel.KindSet_JustInt`,
   278  		`0`,
   279  		false,
   280  	), w, g.AdjCfg, g)
   281  }
   282  
   283  func (g unionKindedReprGenerator) EmitNodeMethodAsFloat(w io.Writer) {
   284  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   285  		`AsFloat`,
   286  		`AsFloat() (float64, error)`,
   287  		`{{- if .Type.RepresentationStrategy.GetMember (Kind "float") }}`,
   288  		`{{- if eq $member.RepresentationBehavior.String "float" }}`,
   289  		`.AsFloat()`,
   290  		`datamodel.KindSet_JustFloat`,
   291  		`0`,
   292  		false,
   293  	), w, g.AdjCfg, g)
   294  }
   295  
   296  func (g unionKindedReprGenerator) EmitNodeMethodAsString(w io.Writer) {
   297  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   298  		`AsString`,
   299  		`AsString() (string, error)`,
   300  		`{{- if .Type.RepresentationStrategy.GetMember (Kind "string") }}`,
   301  		`{{- if eq $member.RepresentationBehavior.String "string" }}`,
   302  		`.AsString()`,
   303  		`datamodel.KindSet_JustString`,
   304  		`""`,
   305  		false,
   306  	), w, g.AdjCfg, g)
   307  }
   308  
   309  func (g unionKindedReprGenerator) EmitNodeMethodAsBytes(w io.Writer) {
   310  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   311  		`AsBytes`,
   312  		`AsBytes() ([]byte, error)`,
   313  		`{{- if .Type.RepresentationStrategy.GetMember (Kind "bytes") }}`,
   314  		`{{- if eq $member.RepresentationBehavior.String "bytes" }}`,
   315  		`.AsBytes()`,
   316  		`datamodel.KindSet_JustBytes`,
   317  		`nil`,
   318  		false,
   319  	), w, g.AdjCfg, g)
   320  }
   321  
   322  func (g unionKindedReprGenerator) EmitNodeMethodAsLink(w io.Writer) {
   323  	doTemplate(kindedUnionNodeMethodTemplateMunge(
   324  		`AsLink`,
   325  		`AsLink() (datamodel.Link, error)`,
   326  		`{{- if .Type.RepresentationStrategy.GetMember (Kind "link") }}`,
   327  		`{{- if eq $member.RepresentationBehavior.String "link" }}`,
   328  		`.AsLink()`,
   329  		`datamodel.KindSet_JustLink`,
   330  		`nil`,
   331  		false,
   332  	), w, g.AdjCfg, g)
   333  }
   334  
   335  func (g unionKindedReprGenerator) EmitNodeMethodPrototype(w io.Writer) {
   336  	emitNodeMethodPrototype_typical(w, g.AdjCfg, g)
   337  }
   338  
   339  func (g unionKindedReprGenerator) EmitNodePrototypeType(w io.Writer) {
   340  	emitNodePrototypeType_typical(w, g.AdjCfg, g)
   341  }
   342  
   343  // --- NodeBuilder and NodeAssembler --->
   344  
   345  func (g unionKindedReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {
   346  	return unionKindedReprBuilderGenerator(g)
   347  }
   348  
   349  type unionKindedReprBuilderGenerator struct {
   350  	AdjCfg  *AdjunctCfg
   351  	PkgName string
   352  	Type    *schema.TypeUnion
   353  }
   354  
   355  func (unionKindedReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates.
   356  
   357  func (g unionKindedReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) {
   358  	emitEmitNodeBuilderType_typical(w, g.AdjCfg, g)
   359  }
   360  func (g unionKindedReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {
   361  	emitNodeBuilderMethods_typical(w, g.AdjCfg, g)
   362  }
   363  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {
   364  	// Much of this is familiar: the 'w', the 'm' are all as usual.
   365  	// Some things may look a little odd here compared to all other assemblers:
   366  	//  we're kinda halfway between what's conventionally seen for a scalar and what's conventionally seen for a recursive.
   367  	// There's no 'maState' or 'laState'-typed fields (which feels like a scalar) because even if we end up acting like a map or list, that state is in the relevant child assembler.
   368  	// We don't even have a 'cm' field, because we can get away with something really funky: we can just copy our own 'm' _pointer_ into children; our doneness and their doneness is the same.
   369  	// We never have to worry about maybeism of our children; the nullable and optional modifiers aren't possible on union members.
   370  	//  (We *do* still have to consider null values though, as null is still a kind, and thus can be routed to one of our members!)
   371  	// 'ca' is as it is in the type-level assembler: technically, not super necessary, except that it allows minimizing the amount of work that resetting needs to do.
   372  	doTemplate(`
   373  		type _{{ .Type | TypeSymbol }}__ReprAssembler struct {
   374  			w *_{{ .Type | TypeSymbol }}
   375  			m *schema.Maybe
   376  
   377  			{{- range $i, $member := .Type.Members }}
   378  			ca{{ add $i 1 }} {{ if (eq (dot.AdjCfg.UnionMemlayout dot.Type) "interface") }}*{{end}}_{{ $member | TypeSymbol }}__ReprAssembler
   379  			{{- end}}
   380  			ca uint
   381  		}
   382  	`, w, g.AdjCfg, g)
   383  	doTemplate(`
   384  		func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {
   385  			switch na.ca {
   386  			case 0:
   387  				return
   388  			{{- range $i, $member := .Type.Members }}
   389  			case {{ add $i 1 }}:
   390  				na.ca{{ add $i 1 }}.reset()
   391  			{{- end}}
   392  			default:
   393  				panic("unreachable")
   394  			}
   395  			na.ca = 0
   396  		}
   397  	`, w, g.AdjCfg, g)
   398  }
   399  
   400  func kindedUnionNodeAssemblerMethodTemplateMunge(
   401  	methodName string, // for error messages
   402  	methodSig string, // output literally
   403  	condClause string, // template condition for the member this should match on
   404  	retClause string, // clause returning the thing (how to delegate methodsig, generally)
   405  	twoReturns bool, // true if a nil should be returned as well as the error
   406  ) string {
   407  	// The value pointed to by `na.m` isn't modified here, because we're sharing it with the child, who should do so.
   408  	//  This also means that value gets checked twice -- once by us, because we need to halt if we've already been used --
   409  	//   and also a second time by the child when we delegate to it, which, unbeknownst to it, is irrelevant.
   410  	//   I don't see a good way to remedy this shy of making more granular (unexported!) methods.  (Might be worth it.)
   411  	//   This probably also isn't the same for all of the assembler methods: the methods we delegate to aren't doing as many check branches when they're for scalars,
   412  	//    because they expected to be used in contexts where many values of the 'm' enum aren't reachable -- an expectation we've suddenly subverted with this path!
   413  	//
   414  	// FUTURE: The error returns here are deeply questionable, and not as helpful as they could be.
   415  	//  ErrNotUnionStructure is about the most applicable thing so far, but it's very freetext.
   416  	//  ErrWrongKind wouldn't fit at all: assumes that we can say what kind of node we have, but this is the one case in the whole system where *we can't*; also, assumes there's one actual correct kind, and that too is false here!
   417  	maybeNilComma := ""
   418  	if twoReturns {
   419  		maybeNilComma += "nil,"
   420  	}
   421  	return `
   422  		func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) ` + methodSig + ` {
   423  			switch *na.m {
   424  			case schema.Maybe_Value, schema.Maybe_Null:
   425  				panic("invalid state: cannot assign into assembler that's already finished")
   426  			case midvalue:
   427  				panic("invalid state: cannot assign into assembler that's already working on a larger structure!")
   428  			}
   429  			{{- $returned := false -}}
   430  			{{- range $i, $member := .Type.Members }}
   431  			` + condClause + `
   432  				{{- if dot.Type | MaybeUsesPtr }}
   433  					if na.w == nil {
   434  						na.w = &_{{ dot.Type | TypeSymbol }}{}
   435  					}
   436  				{{- end}}
   437  				na.ca = {{ add $i 1 }}
   438  				{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) "embedAll") }}
   439  					na.w.tag = {{ add $i 1 }}
   440  					na.ca{{ add $i 1 }}.w = &na.w.x{{ add $i 1 }}
   441  					na.ca{{ add $i 1 }}.m = na.m
   442  					return na.ca{{ add $i 1 }}` + retClause + `
   443  				{{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) "interface") }}
   444  					x := &_{{ $member | TypeSymbol }}{}
   445  					na.w.x = x
   446  					if na.ca{{ add $i 1 }} == nil {
   447  						na.ca{{ add $i 1 }} = &_{{ $member | TypeSymbol }}__ReprAssembler{}
   448  					}
   449  					na.ca{{ add $i 1 }}.w = x
   450  					na.ca{{ add $i 1 }}.m = na.m
   451  					return na.ca{{ add $i 1 }}` + retClause + `
   452  				{{- end}}
   453  				{{- $returned = true -}}
   454  			{{- end }}
   455  			{{- end }}
   456  			{{- if not $returned }}
   457  			return ` + maybeNilComma + ` schema.ErrNotUnionStructure{TypeName: "{{ .PkgName }}.{{ .Type.Name }}.Repr", Detail: "` + methodName + ` called but is not valid for any of the kinds that are valid members of this union"}
   458  			{{- end }}
   459  		}
   460  	`
   461  }
   462  
   463  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(w io.Writer) {
   464  	doTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(
   465  		`BeginMap`,
   466  		`BeginMap(sizeHint int64) (datamodel.MapAssembler, error)`,
   467  		`{{- if eq $member.RepresentationBehavior.String "map" }}`,
   468  		`.BeginMap(sizeHint)`,
   469  		true,
   470  	), w, g.AdjCfg, g)
   471  }
   472  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(w io.Writer) {
   473  	doTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(
   474  		`BeginList`,
   475  		`BeginList(sizeHint int64) (datamodel.ListAssembler, error)`,
   476  		`{{- if eq $member.RepresentationBehavior.String "list" }}`,
   477  		`.BeginList(sizeHint)`,
   478  		true,
   479  	), w, g.AdjCfg, g)
   480  }
   481  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {
   482  	// TODO: I think this may need some special handling to account for if our union is itself used in a nullable circumstance; that should overrule this behavior.
   483  	doTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(
   484  		`AssignNull`,
   485  		`AssignNull() error `,
   486  		`{{- if eq $member.RepresentationBehavior.String "null" }}`,
   487  		`.AssignNull()`,
   488  		false,
   489  	), w, g.AdjCfg, g)
   490  }
   491  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignBool(w io.Writer) {
   492  	doTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(
   493  		`AssignBool`,
   494  		`AssignBool(v bool) error `,
   495  		`{{- if eq $member.RepresentationBehavior.String "bool" }}`,
   496  		`.AssignBool(v)`,
   497  		false,
   498  	), w, g.AdjCfg, g)
   499  }
   500  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignInt(w io.Writer) {
   501  	doTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(
   502  		`AssignInt`,
   503  		`AssignInt(v int64) error `,
   504  		`{{- if eq $member.RepresentationBehavior.String "int" }}`,
   505  		`.AssignInt(v)`,
   506  		false,
   507  	), w, g.AdjCfg, g)
   508  }
   509  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {
   510  	doTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(
   511  		`AssignFloat`,
   512  		`AssignFloat(v float64) error `,
   513  		`{{- if eq $member.RepresentationBehavior.String "float" }}`,
   514  		`.AssignFloat(v)`,
   515  		false,
   516  	), w, g.AdjCfg, g)
   517  }
   518  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(w io.Writer) {
   519  	doTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(
   520  		`AssignString`,
   521  		`AssignString(v string) error `,
   522  		`{{- if eq $member.RepresentationBehavior.String "string" }}`,
   523  		`.AssignString(v)`,
   524  		false,
   525  	), w, g.AdjCfg, g)
   526  }
   527  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {
   528  	doTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(
   529  		`AssignBytes`,
   530  		`AssignBytes(v []byte) error `,
   531  		`{{- if eq $member.RepresentationBehavior.String "bytes" }}`,
   532  		`.AssignBytes(v)`,
   533  		false,
   534  	), w, g.AdjCfg, g)
   535  }
   536  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignLink(w io.Writer) {
   537  	doTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(
   538  		`AssignLink`,
   539  		`AssignLink(v datamodel.Link) error `,
   540  		`{{- if eq $member.RepresentationBehavior.String "link" }}`,
   541  		`.AssignLink(v)`,
   542  		false,
   543  	), w, g.AdjCfg, g)
   544  }
   545  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {
   546  	// This is a very mundane AssignNode: it just calls out to the other methods on this type.
   547  	//  However, even that is a little more exciting than usual: because we can't *necessarily* reject any kind of arg,
   548  	//   we have the whole barrage of switch cases here.  We then leave any particular rejections to those methods.
   549  	//  Several cases could be statically replaced with errors and it would be an improvement.
   550  	//
   551  	// Errors are problematic again, same as is noted in kindedUnionNodeAssemblerMethodTemplateMunge.
   552  	//  We also end up returning errors with other method names due to how we delegate; unfortunate.
   553  	doTemplate(`
   554  		func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignNode(v datamodel.Node) error {
   555  			if v.IsNull() {
   556  				return na.AssignNull()
   557  			}
   558  			if v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {
   559  				switch *na.m {
   560  				case schema.Maybe_Value, schema.Maybe_Null:
   561  					panic("invalid state: cannot assign into assembler that's already finished")
   562  				case midvalue:
   563  					panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!")
   564  				}
   565  				{{- if .Type | MaybeUsesPtr }}
   566  				if na.w == nil {
   567  					na.w = v2
   568  					*na.m = schema.Maybe_Value
   569  					return nil
   570  				}
   571  				{{- end}}
   572  				*na.w = *v2
   573  				*na.m = schema.Maybe_Value
   574  				return nil
   575  			}
   576  			switch v.Kind() {
   577  			case datamodel.Kind_Bool:
   578  				v2, _ := v.AsBool()
   579  				return na.AssignBool(v2)
   580  			case datamodel.Kind_Int:
   581  				v2, _ := v.AsInt()
   582  				return na.AssignInt(v2)
   583  			case datamodel.Kind_Float:
   584  				v2, _ := v.AsFloat()
   585  				return na.AssignFloat(v2)
   586  			case datamodel.Kind_String:
   587  				v2, _ := v.AsString()
   588  				return na.AssignString(v2)
   589  			case datamodel.Kind_Bytes:
   590  				v2, _ := v.AsBytes()
   591  				return na.AssignBytes(v2)
   592  			case datamodel.Kind_Map:
   593  				na, err := na.BeginMap(v.Length())
   594  				if err != nil {
   595  					return err
   596  				}
   597  				itr := v.MapIterator()
   598  				for !itr.Done() {
   599  					k, v, err := itr.Next()
   600  					if err != nil {
   601  						return err
   602  					}
   603  					if err := na.AssembleKey().AssignNode(k); err != nil {
   604  						return err
   605  					}
   606  					if err := na.AssembleValue().AssignNode(v); err != nil {
   607  						return err
   608  					}
   609  				}
   610  				return na.Finish()
   611  			case datamodel.Kind_List:
   612  				na, err := na.BeginList(v.Length())
   613  				if err != nil {
   614  					return err
   615  				}
   616  				itr := v.ListIterator()
   617  				for !itr.Done() {
   618  					_, v, err := itr.Next()
   619  					if err != nil {
   620  						return err
   621  					}
   622  					if err := na.AssembleValue().AssignNode(v); err != nil {
   623  						return err
   624  					}
   625  				}
   626  				return na.Finish()
   627  			case datamodel.Kind_Link:
   628  				v2, _ := v.AsLink()
   629  				return na.AssignLink(v2)
   630  			default:
   631  				panic("unreachable")
   632  			}
   633  		}
   634  	`, w, g.AdjCfg, g)
   635  }
   636  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodPrototype(w io.Writer) {
   637  	doTemplate(`
   638  		func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) Prototype() datamodel.NodePrototype {
   639  			return _{{ .Type | TypeSymbol }}__ReprPrototype{}
   640  		}
   641  	`, w, g.AdjCfg, g)
   642  }
   643  func (g unionKindedReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {
   644  	// somewhat shockingly: nothing.
   645  }