github.com/ipld/go-ipld-prime@v0.21.0/schema/gen/go/genStructReprMap.go (about) 1 package gengo 2 3 import ( 4 "io" 5 "strconv" 6 7 "github.com/ipld/go-ipld-prime/schema" 8 "github.com/ipld/go-ipld-prime/schema/gen/go/mixins" 9 ) 10 11 var _ TypeGenerator = &structReprMapGenerator{} 12 13 func NewStructReprMapGenerator(pkgName string, typ *schema.TypeStruct, adjCfg *AdjunctCfg) TypeGenerator { 14 return structReprMapGenerator{ 15 structGenerator{ 16 adjCfg, 17 mixins.MapTraits{ 18 PkgName: pkgName, 19 TypeName: string(typ.Name()), 20 TypeSymbol: adjCfg.TypeSymbol(typ), 21 }, 22 pkgName, 23 typ, 24 }, 25 } 26 } 27 28 type structReprMapGenerator struct { 29 structGenerator 30 } 31 32 func (g structReprMapGenerator) GetRepresentationNodeGen() NodeGenerator { 33 return structReprMapReprGenerator{ 34 g.AdjCfg, 35 mixins.MapTraits{ 36 PkgName: g.PkgName, 37 TypeName: string(g.Type.Name()) + ".Repr", 38 TypeSymbol: "_" + g.AdjCfg.TypeSymbol(g.Type) + "__Repr", 39 }, 40 g.PkgName, 41 g.Type, 42 } 43 } 44 45 type structReprMapReprGenerator struct { 46 AdjCfg *AdjunctCfg 47 mixins.MapTraits 48 PkgName string 49 Type *schema.TypeStruct 50 } 51 52 func (structReprMapReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates. 53 54 func (g structReprMapReprGenerator) EmitNodeType(w io.Writer) { 55 // The type is structurally the same, but will have a different set of methods. 56 doTemplate(` 57 type _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }} 58 `, w, g.AdjCfg, g) 59 60 // We do also want some constants for our fields; 61 // they'll make iterators able to work faster. 62 // These might be the same strings as the type-level field names 63 // (in fact, they are, unless renames are used)... but that's fine. 64 // We get simpler code by just doing this unconditionally. 65 doTemplate(` 66 var ( 67 {{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}} 68 {{- range $field := .Type.Fields }} 69 fieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}_serial = _String{"{{ $field | $type.RepresentationStrategy.GetFieldKey }}"} 70 {{- end }} 71 ) 72 `, w, g.AdjCfg, g) 73 } 74 75 func (g structReprMapReprGenerator) EmitNodeTypeAssertions(w io.Writer) { 76 doTemplate(` 77 var _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{} 78 `, w, g.AdjCfg, g) 79 } 80 81 func (g structReprMapReprGenerator) EmitNodeMethodLookupByString(w io.Writer) { 82 // Similar to the type-level method, except any absent fields also return ErrNotExists. 83 doTemplate(` 84 func (n *_{{ .Type | TypeSymbol }}__Repr) LookupByString(key string) (datamodel.Node, error) { 85 switch key { 86 {{- range $field := .Type.Fields }} 87 case "{{ $field | $field.Parent.RepresentationStrategy.GetFieldKey }}": 88 {{- if $field.IsOptional }} 89 if n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent { 90 return datamodel.Absent, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)} 91 } 92 {{- end}} 93 {{- if $field.IsNullable }} 94 if n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Null { 95 return datamodel.Null, nil 96 } 97 {{- end}} 98 {{- if $field.IsMaybe }} 99 return n.{{ $field | FieldSymbolLower }}.v.Representation(), nil 100 {{- else}} 101 return n.{{ $field | FieldSymbolLower }}.Representation(), nil 102 {{- end}} 103 {{- end}} 104 default: 105 return nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfString(key)} 106 } 107 } 108 `, w, g.AdjCfg, g) 109 } 110 111 func (g structReprMapReprGenerator) EmitNodeMethodLookupByNode(w io.Writer) { 112 doTemplate(` 113 func (n *_{{ .Type | TypeSymbol }}__Repr) LookupByNode(key datamodel.Node) (datamodel.Node, error) { 114 ks, err := key.AsString() 115 if err != nil { 116 return nil, err 117 } 118 return n.LookupByString(ks) 119 } 120 `, w, g.AdjCfg, g) 121 } 122 123 func (g structReprMapReprGenerator) EmitNodeMethodMapIterator(w io.Writer) { 124 // The 'idx' int is what field we'll yield next. 125 // Note that this iterator doesn't mention fields that are absent. 126 // This makes things a bit trickier -- especially the 'Done' predicate, 127 // since it may have to do lookahead if there's any optionals at the end of the structure! 128 // It also means 'idx' can jump ahead by more than one per Next call in order to skip over absent fields. 129 // TODO : support for implicits is still future work. 130 131 // First: Determine if there are any optionals at all. 132 // If there are none, some control flow symbols need to not be emitted. 133 fields := g.Type.Fields() 134 haveOptionals := false 135 for _, field := range fields { 136 if field.IsOptional() { 137 haveOptionals = true 138 break 139 } 140 } 141 142 // Second: Count how many trailing fields are optional. 143 // The 'Done' predicate gets more complex when in the trailing optionals. 144 fieldCount := len(fields) 145 beginTrailingOptionalField := fieldCount 146 for i := fieldCount - 1; i >= 0; i-- { 147 if !fields[i].IsOptional() { 148 break 149 } 150 beginTrailingOptionalField = i 151 } 152 haveTrailingOptionals := beginTrailingOptionalField < fieldCount 153 154 // Now: finally we can get on with the actual templating. 155 doTemplate(` 156 func (n *_{{ .Type | TypeSymbol }}__Repr) MapIterator() datamodel.MapIterator { 157 {{- if .HaveTrailingOptionals }} 158 end := {{ len .Type.Fields }}`+ 159 func() string { // this next part was too silly in templates due to lack of reverse ranging. 160 v := "\n" 161 for i := fieldCount - 1; i >= beginTrailingOptionalField; i-- { 162 v += "\t\t\tif n." + g.AdjCfg.FieldSymbolLower(fields[i]) + ".m == schema.Maybe_Absent {\n" 163 v += "\t\t\t\tend = " + strconv.Itoa(i) + "\n" 164 v += "\t\t\t} else {\n" 165 v += "\t\t\t\tgoto done\n" 166 v += "\t\t\t}\n" 167 } 168 return v 169 }()+`done: 170 return &_{{ .Type | TypeSymbol }}__ReprMapItr{n, 0, end} 171 {{- else}} 172 return &_{{ .Type | TypeSymbol }}__ReprMapItr{n, 0} 173 {{- end}} 174 } 175 176 type _{{ .Type | TypeSymbol }}__ReprMapItr struct { 177 n *_{{ .Type | TypeSymbol }}__Repr 178 idx int 179 {{if .HaveTrailingOptionals }}end int{{end}} 180 } 181 182 func (itr *_{{ .Type | TypeSymbol }}__ReprMapItr) Next() (k datamodel.Node, v datamodel.Node, _ error) { 183 {{- if not .Type.Fields }} 184 {{- /* TODO: deduplicate all these methods which just error */ -}} 185 return nil, nil, datamodel.ErrIteratorOverread{} 186 {{ else -}} 187 {{ if .HaveOptionals }}advance:{{end -}} 188 if itr.idx >= {{ len .Type.Fields }} { 189 return nil, nil, datamodel.ErrIteratorOverread{} 190 } 191 switch itr.idx { 192 {{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}} 193 {{- range $i, $field := .Type.Fields }} 194 case {{ $i }}: 195 k = &fieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}_serial 196 {{- if $field.IsOptional }} 197 if itr.n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent { 198 itr.idx++ 199 goto advance 200 } 201 {{- end}} 202 {{- if $field.IsNullable }} 203 if itr.n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Null { 204 v = datamodel.Null 205 break 206 } 207 {{- end}} 208 {{- if $field.IsMaybe }} 209 v = itr.n.{{ $field | FieldSymbolLower}}.v.Representation() 210 {{- else}} 211 v = itr.n.{{ $field | FieldSymbolLower}}.Representation() 212 {{- end}} 213 {{- end}} 214 default: 215 panic("unreachable") 216 } 217 itr.idx++ 218 return 219 {{- end}} 220 } 221 {{- if .HaveTrailingOptionals }} 222 func (itr *_{{ .Type | TypeSymbol }}__ReprMapItr) Done() bool { 223 return itr.idx >= itr.end 224 } 225 {{- else}} 226 func (itr *_{{ .Type | TypeSymbol }}__ReprMapItr) Done() bool { 227 return itr.idx >= {{ len .Type.Fields }} 228 } 229 {{- end}} 230 `, w, g.AdjCfg, struct { 231 Type *schema.TypeStruct 232 HaveOptionals bool 233 HaveTrailingOptionals bool 234 BeginTrailingOptionalField int 235 }{ 236 g.Type, 237 haveOptionals, 238 haveTrailingOptionals, 239 beginTrailingOptionalField, 240 }) 241 } 242 243 func (g structReprMapReprGenerator) EmitNodeMethodLength(w io.Writer) { 244 // This is fun: it has to count down for any unset optional fields. 245 // TODO : support for implicits is still future work. 246 doTemplate(` 247 func (rn *_{{ .Type | TypeSymbol }}__Repr) Length() int64 { 248 l := {{ len .Type.Fields }} 249 {{- range $field := .Type.Fields }} 250 {{- if $field.IsOptional }} 251 if rn.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent { 252 l-- 253 } 254 {{- end}} 255 {{- end}} 256 return int64(l) 257 } 258 `, w, g.AdjCfg, g) 259 } 260 261 func (g structReprMapReprGenerator) EmitNodeMethodPrototype(w io.Writer) { 262 emitNodeMethodPrototype_typical(w, g.AdjCfg, g) 263 } 264 265 func (g structReprMapReprGenerator) EmitNodePrototypeType(w io.Writer) { 266 emitNodePrototypeType_typical(w, g.AdjCfg, g) 267 } 268 269 // --- NodeBuilder and NodeAssembler ---> 270 271 func (g structReprMapReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator { 272 return structReprMapReprBuilderGenerator{ 273 g.AdjCfg, 274 mixins.MapAssemblerTraits{ 275 PkgName: g.PkgName, 276 TypeName: g.TypeName, 277 AppliedPrefix: "_" + g.AdjCfg.TypeSymbol(g.Type) + "__Repr", 278 }, 279 g.PkgName, 280 g.Type, 281 } 282 } 283 284 type structReprMapReprBuilderGenerator struct { 285 AdjCfg *AdjunctCfg 286 mixins.MapAssemblerTraits 287 PkgName string 288 Type *schema.TypeStruct 289 } 290 291 func (structReprMapReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates. 292 293 func (g structReprMapReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) { 294 emitEmitNodeBuilderType_typical(w, g.AdjCfg, g) 295 } 296 func (g structReprMapReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) { 297 emitNodeBuilderMethods_typical(w, g.AdjCfg, g) 298 } 299 func (g structReprMapReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) { 300 // - 'w' is the "**w**ip" pointer. 301 // - 'm' is the **m**aybe which communicates our completeness to the parent if we're a child assembler. 302 // - 'state' is what it says on the tin. this is used for the map state (the broad transitions between null, start-map, and finish are handled by 'm' for consistency.) 303 // - 's' is a bitfield for what's been **s**et. 304 // - 'f' is the **f**ocused field that will be assembled next. 305 // 306 // - 'cm' is **c**hild **m**aybe and is used for the completion message from children that aren't allowed to be nullable (for those that are, their own maybe.m is used). 307 // - the 'ca_*' fields embed **c**hild **a**ssemblers -- these are embedded so we can yield pointers to them without causing new allocations. 308 doTemplate(` 309 type _{{ .Type | TypeSymbol }}__ReprAssembler struct { 310 w *_{{ .Type | TypeSymbol }} 311 m *schema.Maybe 312 state maState 313 s int 314 f int 315 316 cm schema.Maybe 317 {{range $field := .Type.Fields -}} 318 ca_{{ $field | FieldSymbolLower }} _{{ $field.Type | TypeSymbol }}__ReprAssembler 319 {{end -}} 320 } 321 322 func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() { 323 na.state = maState_initial 324 na.s = 0 325 {{- range $field := .Type.Fields }} 326 na.ca_{{ $field | FieldSymbolLower }}.reset() 327 {{- end}} 328 } 329 `, w, g.AdjCfg, g) 330 } 331 func (g structReprMapReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(w io.Writer) { 332 emitNodeAssemblerMethodBeginMap_strictoid(w, g.AdjCfg, g) 333 } 334 func (g structReprMapReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) { 335 emitNodeAssemblerMethodAssignNull_recursive(w, g.AdjCfg, g) 336 } 337 func (g structReprMapReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) { 338 // AssignNode goes through three phases: 339 // 1. is it null? Jump over to AssignNull (which may or may not reject it). 340 // 2. is it our own type? Handle specially -- we might be able to do efficient things. 341 // 3. is it the right kind to morph into us? Do so. 342 // 343 // We do not set m=midvalue in phase 3 -- it shouldn't matter unless you're trying to pull off concurrent access, which is wrong and unsafe regardless. 344 doTemplate(` 345 func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignNode(v datamodel.Node) error { 346 if v.IsNull() { 347 return na.AssignNull() 348 } 349 if v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok { 350 switch *na.m { 351 case schema.Maybe_Value, schema.Maybe_Null: 352 panic("invalid state: cannot assign into assembler that's already finished") 353 case midvalue: 354 panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") 355 } 356 {{- if .Type | MaybeUsesPtr }} 357 if na.w == nil { 358 na.w = v2 359 *na.m = schema.Maybe_Value 360 return nil 361 } 362 {{- end}} 363 *na.w = *v2 364 *na.m = schema.Maybe_Value 365 return nil 366 } 367 if v.Kind() != datamodel.Kind_Map { 368 return datamodel.ErrWrongKind{TypeName: "{{ .PkgName }}.{{ .Type.Name }}.Repr", MethodName: "AssignNode", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()} 369 } 370 itr := v.MapIterator() 371 for !itr.Done() { 372 k, v, err := itr.Next() 373 if err != nil { 374 return err 375 } 376 if err := na.AssembleKey().AssignNode(k); err != nil { 377 return err 378 } 379 if err := na.AssembleValue().AssignNode(v); err != nil { 380 return err 381 } 382 } 383 return na.Finish() 384 } 385 `, w, g.AdjCfg, g) 386 } 387 func (g structReprMapReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) { 388 g.emitMapAssemblerChildTidyHelper(w) 389 g.emitMapAssemblerMethods(w) 390 g.emitKeyAssembler(w) 391 } 392 func (g structReprMapReprBuilderGenerator) emitMapAssemblerChildTidyHelper(w io.Writer) { 393 // This is exactly the same as the matching method on the type-level assembler; 394 // everything that differs happens to be hidden behind the 'f' indirection, which is numeric. 395 doTemplate(` 396 func (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) valueFinishTidy() bool { 397 switch ma.f { 398 {{- range $i, $field := .Type.Fields }} 399 case {{ $i }}: 400 {{- if $field.IsNullable }} 401 switch ma.w.{{ $field | FieldSymbolLower }}.m { 402 case schema.Maybe_Null: 403 ma.state = maState_initial 404 return true 405 case schema.Maybe_Value: 406 {{- if (MaybeUsesPtr $field.Type) }} 407 ma.w.{{ $field | FieldSymbolLower }}.v = ma.ca_{{ $field | FieldSymbolLower }}.w 408 {{- end}} 409 ma.state = maState_initial 410 return true 411 default: 412 return false 413 } 414 {{- else if $field.IsOptional }} 415 switch ma.w.{{ $field | FieldSymbolLower }}.m { 416 case schema.Maybe_Value: 417 {{- if (MaybeUsesPtr $field.Type) }} 418 ma.w.{{ $field | FieldSymbolLower }}.v = ma.ca_{{ $field | FieldSymbolLower }}.w 419 {{- end}} 420 ma.state = maState_initial 421 return true 422 default: 423 return false 424 } 425 {{- else}} 426 switch ma.cm { 427 case schema.Maybe_Value: 428 {{- /* while defense in depth here might avoid some 'wat' outcomes, it's not strictly necessary for safety */ -}} 429 {{- /* ma.ca_{{ $field | FieldSymbolLower }}.w = nil */ -}} 430 {{- /* ma.ca_{{ $field | FieldSymbolLower }}.m = nil */ -}} 431 ma.cm = schema.Maybe_Absent 432 ma.state = maState_initial 433 return true 434 default: 435 return false 436 } 437 {{- end}} 438 {{- end}} 439 default: 440 panic("unreachable") 441 } 442 } 443 `, w, g.AdjCfg, g) 444 } 445 func (g structReprMapReprBuilderGenerator) emitMapAssemblerMethods(w io.Writer) { 446 // FUTURE: some of the setup of the child assemblers could probably be DRY'd up. 447 doTemplate(` 448 func (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) { 449 switch ma.state { 450 case maState_initial: 451 // carry on 452 case maState_midKey: 453 panic("invalid state: AssembleEntry cannot be called when in the middle of assembling another key") 454 case maState_expectValue: 455 panic("invalid state: AssembleEntry cannot be called when expecting start of value assembly") 456 case maState_midValue: 457 if !ma.valueFinishTidy() { 458 panic("invalid state: AssembleEntry cannot be called when in the middle of assembling a value") 459 } // if tidy success: carry on 460 case maState_finished: 461 panic("invalid state: AssembleEntry cannot be called on an assembler that's already finished") 462 } 463 {{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}} 464 {{- if .Type.Fields }} 465 switch k { 466 {{- range $i, $field := .Type.Fields }} 467 case "{{ $field | $type.RepresentationStrategy.GetFieldKey }}": 468 if ma.s & fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} != 0 { 469 return nil, datamodel.ErrRepeatedMapKey{Key: &fieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}_serial} 470 } 471 ma.s += fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} 472 ma.state = maState_midValue 473 ma.f = {{ $i }} 474 {{- if $field.IsMaybe }} 475 ma.ca_{{ $field | FieldSymbolLower }}.w = {{if not (MaybeUsesPtr $field.Type) }}&{{end}}ma.w.{{ $field | FieldSymbolLower }}.v 476 ma.ca_{{ $field | FieldSymbolLower }}.m = &ma.w.{{ $field | FieldSymbolLower }}.m 477 {{if $field.IsNullable }}ma.w.{{ $field | FieldSymbolLower }}.m = allowNull{{end}} 478 {{- else}} 479 ma.ca_{{ $field | FieldSymbolLower }}.w = &ma.w.{{ $field | FieldSymbolLower }} 480 ma.ca_{{ $field | FieldSymbolLower }}.m = &ma.cm 481 {{- end}} 482 return &ma.ca_{{ $field | FieldSymbolLower }}, nil 483 {{- end}} 484 default: 485 } 486 {{- end}} 487 return nil, schema.ErrInvalidKey{TypeName:"{{ .PkgName }}.{{ .Type.Name }}.Repr", Key:&_String{k}} 488 } 489 func (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) AssembleKey() datamodel.NodeAssembler { 490 switch ma.state { 491 case maState_initial: 492 // carry on 493 case maState_midKey: 494 panic("invalid state: AssembleKey cannot be called when in the middle of assembling another key") 495 case maState_expectValue: 496 panic("invalid state: AssembleKey cannot be called when expecting start of value assembly") 497 case maState_midValue: 498 if !ma.valueFinishTidy() { 499 panic("invalid state: AssembleKey cannot be called when in the middle of assembling a value") 500 } // if tidy success: carry on 501 case maState_finished: 502 panic("invalid state: AssembleKey cannot be called on an assembler that's already finished") 503 } 504 ma.state = maState_midKey 505 return (*_{{ .Type | TypeSymbol }}__ReprKeyAssembler)(ma) 506 } 507 func (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) AssembleValue() datamodel.NodeAssembler { 508 switch ma.state { 509 case maState_initial: 510 panic("invalid state: AssembleValue cannot be called when no key is primed") 511 case maState_midKey: 512 panic("invalid state: AssembleValue cannot be called when in the middle of assembling a key") 513 case maState_expectValue: 514 // carry on 515 case maState_midValue: 516 panic("invalid state: AssembleValue cannot be called when in the middle of assembling another value") 517 case maState_finished: 518 panic("invalid state: AssembleValue cannot be called on an assembler that's already finished") 519 } 520 ma.state = maState_midValue 521 switch ma.f { 522 {{- range $i, $field := .Type.Fields }} 523 case {{ $i }}: 524 {{- if $field.IsMaybe }} 525 ma.ca_{{ $field | FieldSymbolLower }}.w = {{if not (MaybeUsesPtr $field.Type) }}&{{end}}ma.w.{{ $field | FieldSymbolLower }}.v 526 ma.ca_{{ $field | FieldSymbolLower }}.m = &ma.w.{{ $field | FieldSymbolLower }}.m 527 {{if $field.IsNullable }}ma.w.{{ $field | FieldSymbolLower }}.m = allowNull{{end}} 528 {{- else}} 529 ma.ca_{{ $field | FieldSymbolLower }}.w = &ma.w.{{ $field | FieldSymbolLower }} 530 ma.ca_{{ $field | FieldSymbolLower }}.m = &ma.cm 531 {{- end}} 532 return &ma.ca_{{ $field | FieldSymbolLower }} 533 {{- end}} 534 default: 535 panic("unreachable") 536 } 537 } 538 func (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) Finish() error { 539 switch ma.state { 540 case maState_initial: 541 // carry on 542 case maState_midKey: 543 panic("invalid state: Finish cannot be called when in the middle of assembling a key") 544 case maState_expectValue: 545 panic("invalid state: Finish cannot be called when expecting start of value assembly") 546 case maState_midValue: 547 if !ma.valueFinishTidy() { 548 panic("invalid state: Finish cannot be called when in the middle of assembling a value") 549 } // if tidy success: carry on 550 case maState_finished: 551 panic("invalid state: Finish cannot be called on an assembler that's already finished") 552 } 553 if ma.s & fieldBits__{{ $type | TypeSymbol }}_sufficient != fieldBits__{{ $type | TypeSymbol }}_sufficient { 554 err := schema.ErrMissingRequiredField{Missing: make([]string, 0)} 555 {{- range $i, $field := .Type.Fields }} 556 {{- if not $field.IsMaybe}} 557 if ma.s & fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} == 0 { 558 {{- if $field | $type.RepresentationStrategy.FieldHasRename }} 559 err.Missing = append(err.Missing, "{{ $field.Name }} (serial:\"{{ $field | $type.RepresentationStrategy.GetFieldKey }}\")") 560 {{- else}} 561 err.Missing = append(err.Missing, "{{ $field.Name }}") 562 {{- end}} 563 } 564 {{- end}} 565 {{- end}} 566 return err 567 } 568 ma.state = maState_finished 569 *ma.m = schema.Maybe_Value 570 return nil 571 } 572 func (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) KeyPrototype() datamodel.NodePrototype { 573 return _String__Prototype{} 574 } 575 func (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) ValuePrototype(k string) datamodel.NodePrototype { 576 panic("todo structbuilder mapassembler repr valueprototype") 577 } 578 `, w, g.AdjCfg, g) 579 } 580 func (g structReprMapReprBuilderGenerator) emitKeyAssembler(w io.Writer) { 581 doTemplate(` 582 type _{{ .Type | TypeSymbol }}__ReprKeyAssembler _{{ .Type | TypeSymbol }}__ReprAssembler 583 `, w, g.AdjCfg, g) 584 stubs := mixins.StringAssemblerTraits{ 585 PkgName: g.PkgName, 586 TypeName: g.TypeName + ".KeyAssembler", // ".Repr" is already in `g.TypeName`, so don't stutter the "Repr" part. 587 AppliedPrefix: "_" + g.AdjCfg.TypeSymbol(g.Type) + "__ReprKey", 588 } 589 // This key assembler can disregard any idea of complex keys because it's at the representation level! 590 // Map keys must always be plain strings at the representation level. 591 stubs.EmitNodeAssemblerMethodBeginMap(w) 592 stubs.EmitNodeAssemblerMethodBeginList(w) 593 stubs.EmitNodeAssemblerMethodAssignNull(w) 594 stubs.EmitNodeAssemblerMethodAssignBool(w) 595 stubs.EmitNodeAssemblerMethodAssignInt(w) 596 stubs.EmitNodeAssemblerMethodAssignFloat(w) 597 doTemplate(` 598 func (ka *_{{ .Type | TypeSymbol }}__ReprKeyAssembler) AssignString(k string) error { 599 if ka.state != maState_midKey { 600 panic("misuse: KeyAssembler held beyond its valid lifetime") 601 } 602 {{- if .Type.Fields }} 603 switch k { 604 {{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}} 605 {{- range $i, $field := .Type.Fields }} 606 case "{{ $field | $type.RepresentationStrategy.GetFieldKey }}": 607 if ka.s & fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} != 0 { 608 return datamodel.ErrRepeatedMapKey{Key: &fieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}_serial} 609 } 610 ka.s += fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} 611 ka.state = maState_expectValue 612 ka.f = {{ $i }} 613 return nil 614 {{- end }} 615 } 616 {{- end }} 617 return schema.ErrInvalidKey{TypeName:"{{ .PkgName }}.{{ .Type.Name }}.Repr", Key:&_String{k}} 618 } 619 `, w, g.AdjCfg, g) 620 stubs.EmitNodeAssemblerMethodAssignBytes(w) 621 stubs.EmitNodeAssemblerMethodAssignLink(w) 622 doTemplate(` 623 func (ka *_{{ .Type | TypeSymbol }}__ReprKeyAssembler) AssignNode(v datamodel.Node) error { 624 if v2, err := v.AsString(); err != nil { 625 return err 626 } else { 627 return ka.AssignString(v2) 628 } 629 } 630 func (_{{ .Type | TypeSymbol }}__ReprKeyAssembler) Prototype() datamodel.NodePrototype { 631 return _String__Prototype{} 632 } 633 `, w, g.AdjCfg, g) 634 }