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 }