github.com/ipld/go-ipld-prime@v0.21.0/node/bindnode/node.go (about) 1 package bindnode 2 3 import ( 4 "fmt" 5 "math" 6 "reflect" 7 "runtime" 8 "strings" 9 10 "github.com/ipfs/go-cid" 11 "github.com/ipld/go-ipld-prime/datamodel" 12 cidlink "github.com/ipld/go-ipld-prime/linking/cid" 13 "github.com/ipld/go-ipld-prime/node/basicnode" 14 "github.com/ipld/go-ipld-prime/node/mixins" 15 "github.com/ipld/go-ipld-prime/schema" 16 ) 17 18 // Assert that we implement all the interfaces as expected. 19 // Grouped by the interfaces to implement, roughly. 20 var ( 21 _ datamodel.NodePrototype = (*_prototype)(nil) 22 _ schema.TypedPrototype = (*_prototype)(nil) 23 _ datamodel.NodePrototype = (*_prototypeRepr)(nil) 24 25 _ datamodel.Node = (*_node)(nil) 26 _ schema.TypedNode = (*_node)(nil) 27 _ datamodel.Node = (*_nodeRepr)(nil) 28 29 _ datamodel.Node = (*_uintNode)(nil) 30 _ schema.TypedNode = (*_uintNode)(nil) 31 _ datamodel.UintNode = (*_uintNode)(nil) 32 _ datamodel.Node = (*_uintNodeRepr)(nil) 33 _ datamodel.UintNode = (*_uintNodeRepr)(nil) 34 35 _ datamodel.NodeBuilder = (*_builder)(nil) 36 _ datamodel.NodeBuilder = (*_builderRepr)(nil) 37 _ datamodel.NodeAssembler = (*_assembler)(nil) 38 _ datamodel.NodeAssembler = (*_assemblerRepr)(nil) 39 _ datamodel.NodeAssembler = (*_errorAssembler)(nil) 40 _ datamodel.NodeAssembler = (*_listpairsFieldAssemblerRepr)(nil) 41 42 _ datamodel.MapAssembler = (*_structAssembler)(nil) 43 _ datamodel.MapAssembler = (*_structAssemblerRepr)(nil) 44 _ datamodel.MapIterator = (*_structIterator)(nil) 45 _ datamodel.MapIterator = (*_structIteratorRepr)(nil) 46 47 _ datamodel.ListAssembler = (*_listAssembler)(nil) 48 _ datamodel.ListAssembler = (*_listAssemblerRepr)(nil) 49 _ datamodel.ListAssembler = (*_listStructAssemblerRepr)(nil) 50 _ datamodel.ListAssembler = (*_listpairsFieldListAssemblerRepr)(nil) 51 _ datamodel.ListIterator = (*_listIterator)(nil) 52 _ datamodel.ListIterator = (*_tupleIteratorRepr)(nil) 53 _ datamodel.ListIterator = (*_listpairsIteratorRepr)(nil) 54 55 _ datamodel.MapAssembler = (*_unionAssembler)(nil) 56 _ datamodel.MapAssembler = (*_unionAssemblerRepr)(nil) 57 _ datamodel.MapIterator = (*_unionIterator)(nil) 58 _ datamodel.MapIterator = (*_unionIteratorRepr)(nil) 59 ) 60 61 type _prototype struct { 62 cfg config 63 schemaType schema.Type 64 goType reflect.Type // non-pointer 65 } 66 67 func (w *_prototype) NewBuilder() datamodel.NodeBuilder { 68 return &_builder{_assembler{ 69 cfg: w.cfg, 70 schemaType: w.schemaType, 71 val: reflect.New(w.goType).Elem(), 72 }} 73 } 74 75 func (w *_prototype) Type() schema.Type { 76 return w.schemaType 77 } 78 79 func (w *_prototype) Representation() datamodel.NodePrototype { 80 return (*_prototypeRepr)(w) 81 } 82 83 type _node struct { 84 cfg config 85 schemaType schema.Type 86 87 val reflect.Value // non-pointer 88 } 89 90 // TODO: only expose TypedNode methods if the schema was explicit. 91 // type _typedNode struct { 92 // _node 93 // } 94 95 func newNode(cfg config, schemaType schema.Type, val reflect.Value) schema.TypedNode { 96 if schemaType.TypeKind() == schema.TypeKind_Int && nonPtrVal(val).Kind() == reflect.Uint64 { 97 // special case for uint64 values so we can handle the >int64 range 98 // we give this treatment to all uint64s, regardless of current value 99 // because we have no guarantees the value won't change underneath us 100 return &_uintNode{ 101 cfg: cfg, 102 schemaType: schemaType, 103 val: val, 104 } 105 } 106 return &_node{cfg, schemaType, val} 107 } 108 109 func (w *_node) Type() schema.Type { 110 return w.schemaType 111 } 112 113 func (w *_node) Representation() datamodel.Node { 114 return (*_nodeRepr)(w) 115 } 116 117 func (w *_node) Kind() datamodel.Kind { 118 return actualKind(w.schemaType) 119 } 120 121 // matching schema level types to data model kinds, since our Node and Builder 122 // interfaces operate on kinds 123 func compatibleKind(schemaType schema.Type, kind datamodel.Kind) error { 124 switch sch := schemaType.(type) { 125 case *schema.TypeAny: 126 return nil 127 default: 128 actual := actualKind(sch) // ActsLike data model 129 if actual == kind { 130 return nil 131 } 132 133 // Error 134 methodName := "" 135 if pc, _, _, ok := runtime.Caller(1); ok { 136 if fn := runtime.FuncForPC(pc); fn != nil { 137 methodName = fn.Name() 138 // Go from "pkg/path.Type.Method" to just "Method". 139 methodName = methodName[strings.LastIndexByte(methodName, '.')+1:] 140 } 141 } 142 return datamodel.ErrWrongKind{ 143 TypeName: schemaType.Name(), 144 MethodName: methodName, 145 AppropriateKind: datamodel.KindSet{kind}, 146 ActualKind: actual, 147 } 148 } 149 } 150 151 func actualKind(schemaType schema.Type) datamodel.Kind { 152 return schemaType.TypeKind().ActsLike() 153 } 154 155 func nonPtrVal(val reflect.Value) reflect.Value { 156 // TODO: support **T as well as *T? 157 if val.Kind() == reflect.Ptr { 158 if val.IsNil() { 159 // TODO: error in this case? 160 return reflect.Value{} 161 } 162 val = val.Elem() 163 } 164 return val 165 } 166 167 func ptrVal(val reflect.Value) reflect.Value { 168 if val.Kind() == reflect.Ptr { 169 return val 170 } 171 return val.Addr() 172 } 173 174 func nonPtrType(val reflect.Value) reflect.Type { 175 typ := val.Type() 176 if typ.Kind() == reflect.Ptr { 177 return typ.Elem() 178 } 179 return typ 180 } 181 182 // where we need to cal Set(), ensure the Value we're setting is a pointer or 183 // not, depending on the field we're setting into. 184 func matchSettable(val interface{}, to reflect.Value) reflect.Value { 185 setVal := nonPtrVal(reflect.ValueOf(val)) 186 if !setVal.Type().AssignableTo(to.Type()) && setVal.Type().ConvertibleTo(to.Type()) { 187 setVal = setVal.Convert(to.Type()) 188 } 189 return setVal 190 } 191 192 func (w *_node) LookupByString(key string) (datamodel.Node, error) { 193 switch typ := w.schemaType.(type) { 194 case *schema.TypeStruct: 195 field := typ.Field(key) 196 if field == nil { 197 return nil, schema.ErrInvalidKey{ 198 TypeName: typ.Name(), 199 Key: basicnode.NewString(key), 200 } 201 } 202 fval := nonPtrVal(w.val).FieldByName(fieldNameFromSchema(key)) 203 if !fval.IsValid() { 204 return nil, fmt.Errorf("bindnode TODO: go-schema mismatch") 205 } 206 if field.IsOptional() { 207 if fval.IsNil() { 208 return datamodel.Absent, nil 209 } 210 if fval.Kind() == reflect.Ptr { 211 fval = fval.Elem() 212 } 213 } 214 if field.IsNullable() { 215 if fval.IsNil() { 216 return datamodel.Null, nil 217 } 218 if fval.Kind() == reflect.Ptr { 219 fval = fval.Elem() 220 } 221 } 222 if _, ok := field.Type().(*schema.TypeAny); ok { 223 if customConverter := w.cfg.converterFor(fval); customConverter != nil { 224 // field is an Any and we have a custom type converter for the type 225 return customConverter.customToAny(ptrVal(fval).Interface()) 226 } 227 // field is an Any, safely assume a Node in fval 228 return nonPtrVal(fval).Interface().(datamodel.Node), nil 229 } 230 return newNode(w.cfg, field.Type(), fval), nil 231 case *schema.TypeMap: 232 // maps can only be structs with a Values map 233 var kval reflect.Value 234 valuesVal := nonPtrVal(w.val).FieldByName("Values") 235 switch ktyp := typ.KeyType().(type) { 236 case *schema.TypeString: 237 // plain String keys, so safely use the map key as is 238 kval = reflect.ValueOf(key) 239 default: 240 // key is something other than a string that we need to assemble via 241 // the string representation form, use _assemblerRepr to reverse from 242 // string to the type that indexes the map 243 asm := &_assembler{ 244 cfg: w.cfg, 245 schemaType: ktyp, 246 val: reflect.New(valuesVal.Type().Key()).Elem(), 247 } 248 if err := (*_assemblerRepr)(asm).AssignString(key); err != nil { 249 return nil, err 250 } 251 kval = asm.val 252 } 253 fval := valuesVal.MapIndex(kval) 254 if !fval.IsValid() { // not found 255 return nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)} 256 } 257 // TODO: Error/panic if fval.IsNil() && !typ.ValueIsNullable()? 258 // Otherwise we could have two non-equal Go values (nil map, 259 // non-nil-but-empty map) which represent the exact same IPLD 260 // node when the field is not nullable. 261 if typ.ValueIsNullable() { 262 if fval.IsNil() { 263 return datamodel.Null, nil 264 } 265 fval = fval.Elem() 266 } 267 if _, ok := typ.ValueType().(*schema.TypeAny); ok { 268 if customConverter := w.cfg.converterFor(fval); customConverter != nil { 269 // value is an Any and we have a custom type converter for the type 270 return customConverter.customToAny(ptrVal(fval).Interface()) 271 } 272 // value is an Any, safely assume a Node in fval 273 return nonPtrVal(fval).Interface().(datamodel.Node), nil 274 } 275 return newNode(w.cfg, typ.ValueType(), fval), nil 276 case *schema.TypeUnion: 277 // treat a union similar to a struct, but we have the member names more 278 // easily accessible to match to 'key' 279 var idx int 280 var mtyp schema.Type 281 for i, member := range typ.Members() { 282 if member.Name() == key { 283 idx = i 284 mtyp = member 285 break 286 } 287 } 288 if mtyp == nil { // not found 289 return nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)} 290 } 291 // TODO: we could look up the right Go field straight away via idx. 292 haveIdx, mval := unionMember(nonPtrVal(w.val)) 293 if haveIdx != idx { // mismatching type 294 return nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)} 295 } 296 return newNode(w.cfg, mtyp, mval), nil 297 } 298 return nil, datamodel.ErrWrongKind{ 299 TypeName: w.schemaType.Name(), 300 MethodName: "LookupByString", 301 AppropriateKind: datamodel.KindSet_JustMap, 302 ActualKind: w.Kind(), 303 } 304 } 305 306 var invalidValue reflect.Value 307 308 // unionMember finds which union member is set in the corresponding Go struct. 309 func unionMember(val reflect.Value) (int, reflect.Value) { 310 // The first non-nil field is a match. 311 for i := 0; i < val.NumField(); i++ { 312 elemVal := val.Field(i) 313 if elemVal.Kind() != reflect.Ptr { 314 panic("bindnode bug: found unexpected non-pointer in a union field") 315 } 316 if elemVal.IsNil() { 317 continue 318 } 319 return i, elemVal.Elem() 320 } 321 return -1, invalidValue 322 } 323 324 func unionSetMember(val reflect.Value, memberIdx int, memberPtr reflect.Value) { 325 // Reset the entire union struct to zero, to clear any non-nil pointers. 326 val.Set(reflect.Zero(val.Type())) 327 328 // Set the index pointer to the given value. 329 val.Field(memberIdx).Set(memberPtr) 330 } 331 332 func (w *_node) LookupByIndex(idx int64) (datamodel.Node, error) { 333 switch typ := w.schemaType.(type) { 334 case *schema.TypeList: 335 val := nonPtrVal(w.val) 336 // we should be able assume that val is something we can Len() and Index() 337 if idx < 0 || int(idx) >= val.Len() { 338 return nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfInt(idx)} 339 } 340 val = val.Index(int(idx)) 341 _, isAny := typ.ValueType().(*schema.TypeAny) 342 if isAny { 343 if customConverter := w.cfg.converterFor(val); customConverter != nil { 344 // values are Any and we have a converter for this type that will give us 345 // a datamodel.Node 346 return customConverter.customToAny(ptrVal(val).Interface()) 347 } 348 } 349 if typ.ValueIsNullable() { 350 if val.IsNil() { 351 return datamodel.Null, nil 352 } 353 // nullable elements are assumed to be pointers 354 val = val.Elem() 355 } 356 if isAny { 357 // Any always yields a plain datamodel.Node 358 return nonPtrVal(val).Interface().(datamodel.Node), nil 359 } 360 return newNode(w.cfg, typ.ValueType(), val), nil 361 } 362 return nil, datamodel.ErrWrongKind{ 363 TypeName: w.schemaType.Name(), 364 MethodName: "LookupByIndex", 365 AppropriateKind: datamodel.KindSet_JustList, 366 ActualKind: w.Kind(), 367 } 368 } 369 370 func (w *_node) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) { 371 switch w.Kind() { 372 case datamodel.Kind_Map: 373 return w.LookupByString(seg.String()) 374 case datamodel.Kind_List: 375 idx, err := seg.Index() 376 if err != nil { 377 return nil, err 378 } 379 return w.LookupByIndex(idx) 380 } 381 return nil, datamodel.ErrWrongKind{ 382 TypeName: w.schemaType.Name(), 383 MethodName: "LookupBySegment", 384 AppropriateKind: datamodel.KindSet_Recursive, 385 ActualKind: w.Kind(), 386 } 387 } 388 389 func (w *_node) LookupByNode(key datamodel.Node) (datamodel.Node, error) { 390 switch w.Kind() { 391 case datamodel.Kind_Map: 392 s, err := key.AsString() 393 if err != nil { 394 return nil, err 395 } 396 return w.LookupByString(s) 397 case datamodel.Kind_List: 398 i, err := key.AsInt() 399 if err != nil { 400 return nil, err 401 } 402 return w.LookupByIndex(i) 403 } 404 return nil, datamodel.ErrWrongKind{ 405 TypeName: w.schemaType.Name(), 406 MethodName: "LookupByNode", 407 AppropriateKind: datamodel.KindSet_Recursive, 408 ActualKind: w.Kind(), 409 } 410 } 411 412 func (w *_node) MapIterator() datamodel.MapIterator { 413 val := nonPtrVal(w.val) 414 // structs, unions and maps can all iterate but they each have different 415 // access semantics for the underlying type, so we need a different iterator 416 // for each 417 switch typ := w.schemaType.(type) { 418 case *schema.TypeStruct: 419 return &_structIterator{ 420 cfg: w.cfg, 421 schemaType: typ, 422 fields: typ.Fields(), 423 val: val, 424 } 425 case *schema.TypeUnion: 426 return &_unionIterator{ 427 cfg: w.cfg, 428 schemaType: typ, 429 members: typ.Members(), 430 val: val, 431 } 432 case *schema.TypeMap: 433 // we can assume a: struct{Keys []string, Values map[x]y} 434 return &_mapIterator{ 435 cfg: w.cfg, 436 schemaType: typ, 437 keysVal: val.FieldByName("Keys"), 438 valuesVal: val.FieldByName("Values"), 439 } 440 } 441 return nil 442 } 443 444 func (w *_node) ListIterator() datamodel.ListIterator { 445 val := nonPtrVal(w.val) 446 switch typ := w.schemaType.(type) { 447 case *schema.TypeList: 448 return &_listIterator{cfg: w.cfg, schemaType: typ, val: val} 449 } 450 return nil 451 } 452 453 func (w *_node) Length() int64 { 454 val := nonPtrVal(w.val) 455 switch w.Kind() { 456 case datamodel.Kind_Map: 457 switch typ := w.schemaType.(type) { 458 case *schema.TypeStruct: 459 return int64(len(typ.Fields())) 460 case *schema.TypeUnion: 461 return 1 462 } 463 return int64(val.FieldByName("Keys").Len()) 464 case datamodel.Kind_List: 465 return int64(val.Len()) 466 } 467 return -1 468 } 469 470 // TODO: better story around pointers and absent/null 471 472 func (w *_node) IsAbsent() bool { 473 return false 474 } 475 476 func (w *_node) IsNull() bool { 477 return false 478 } 479 480 // The AsX methods are matter of fetching the non-pointer form of the underlying 481 // value and returning the appropriate Go type. The user may have registered 482 // custom converters for the kind being converted, in which case the underlying 483 // type may not be the type we need, but the converter will supply it for us. 484 485 func (w *_node) AsBool() (bool, error) { 486 if err := compatibleKind(w.schemaType, datamodel.Kind_Bool); err != nil { 487 return false, err 488 } 489 if customConverter := w.cfg.converterFor(w.val); customConverter != nil { 490 // user has registered a converter that takes the underlying type and returns a bool 491 return customConverter.customToBool(ptrVal(w.val).Interface()) 492 } 493 return nonPtrVal(w.val).Bool(), nil 494 } 495 496 func (w *_node) AsInt() (int64, error) { 497 if err := compatibleKind(w.schemaType, datamodel.Kind_Int); err != nil { 498 return 0, err 499 } 500 if customConverter := w.cfg.converterFor(w.val); customConverter != nil { 501 // user has registered a converter that takes the underlying type and returns an int 502 return customConverter.customToInt(ptrVal(w.val).Interface()) 503 } 504 val := nonPtrVal(w.val) 505 if kindUint[val.Kind()] { 506 u := val.Uint() 507 if u > math.MaxInt64 { 508 return 0, fmt.Errorf("bindnode: integer overflow, %d is too large for an int64", u) 509 } 510 return int64(u), nil 511 } 512 return val.Int(), nil 513 } 514 515 func (w *_node) AsFloat() (float64, error) { 516 if err := compatibleKind(w.schemaType, datamodel.Kind_Float); err != nil { 517 return 0, err 518 } 519 if customConverter := w.cfg.converterFor(w.val); customConverter != nil { 520 // user has registered a converter that takes the underlying type and returns a float 521 return customConverter.customToFloat(ptrVal(w.val).Interface()) 522 } 523 return nonPtrVal(w.val).Float(), nil 524 } 525 526 func (w *_node) AsString() (string, error) { 527 if err := compatibleKind(w.schemaType, datamodel.Kind_String); err != nil { 528 return "", err 529 } 530 if customConverter := w.cfg.converterFor(w.val); customConverter != nil { 531 // user has registered a converter that takes the underlying type and returns a string 532 return customConverter.customToString(ptrVal(w.val).Interface()) 533 } 534 return nonPtrVal(w.val).String(), nil 535 } 536 537 func (w *_node) AsBytes() ([]byte, error) { 538 if err := compatibleKind(w.schemaType, datamodel.Kind_Bytes); err != nil { 539 return nil, err 540 } 541 if customConverter := w.cfg.converterFor(w.val); customConverter != nil { 542 // user has registered a converter that takes the underlying type and returns a []byte 543 return customConverter.customToBytes(ptrVal(w.val).Interface()) 544 } 545 return nonPtrVal(w.val).Bytes(), nil 546 } 547 548 func (w *_node) AsLink() (datamodel.Link, error) { 549 if err := compatibleKind(w.schemaType, datamodel.Kind_Link); err != nil { 550 return nil, err 551 } 552 if customConverter := w.cfg.converterFor(w.val); customConverter != nil { 553 // user has registered a converter that takes the underlying type and returns a cid.Cid 554 cid, err := customConverter.customToLink(ptrVal(w.val).Interface()) 555 if err != nil { 556 return nil, err 557 } 558 return cidlink.Link{Cid: cid}, nil 559 } 560 switch val := nonPtrVal(w.val).Interface().(type) { 561 case datamodel.Link: 562 return val, nil 563 case cid.Cid: 564 return cidlink.Link{Cid: val}, nil 565 default: 566 return nil, fmt.Errorf("bindnode: unexpected link type %T", val) 567 } 568 } 569 570 func (w *_node) Prototype() datamodel.NodePrototype { 571 return &_prototype{cfg: w.cfg, schemaType: w.schemaType, goType: w.val.Type()} 572 } 573 574 type _builder struct { 575 _assembler 576 } 577 578 func (w *_builder) Build() datamodel.Node { 579 // TODO: should we panic if no Assign call was made, just like codegen? 580 return newNode(w.cfg, w.schemaType, w.val) 581 } 582 583 func (w *_builder) Reset() { 584 panic("bindnode TODO: Reset") 585 } 586 587 type _assembler struct { 588 cfg config 589 schemaType schema.Type 590 val reflect.Value // non-pointer 591 592 // finish is used as an optional post-assemble step. 593 // For example, assigning to a kinded union uses a finish func 594 // to set the right union member in the Go union struct, 595 // which isn't known before the assemble has finished. 596 finish func() error 597 598 nullable bool // true if field or map value is nullable 599 } 600 601 // createNonPtrVal is used for Set() operations on the underlying value 602 func (w *_assembler) createNonPtrVal() reflect.Value { 603 val := w.val 604 // TODO: if val is not a pointer, we reuse its value. 605 // If it is a pointer, we allocate a new one and replace it. 606 // We should probably never reuse the existing value. 607 608 // TODO: support **T as well as *T? 609 if val.Kind() == reflect.Ptr { 610 // TODO: Sometimes we call createNonPtrVal before an assignment actually 611 // happens. Does that matter? 612 // If it matters and we only want to modify the destination value on 613 // success, then we should make use of the "finish" func. 614 val.Set(reflect.New(val.Type().Elem())) 615 val = val.Elem() 616 } 617 return val 618 } 619 620 func (w *_assembler) Representation() datamodel.NodeAssembler { 621 return (*_assemblerRepr)(w) 622 } 623 624 // basicMapAssembler is for assembling basicnode values, it's only use is for 625 // Any fields that end up needing a BeginMap() 626 type basicMapAssembler struct { 627 datamodel.MapAssembler 628 629 builder datamodel.NodeBuilder 630 parent *_assembler 631 converter *converter 632 } 633 634 func (w *basicMapAssembler) Finish() error { 635 if err := w.MapAssembler.Finish(); err != nil { 636 return err 637 } 638 basicNode := w.builder.Build() 639 if w.converter != nil { 640 // we can assume an Any converter because basicMapAssembler is only for Any 641 // the user has registered the ability to convert a datamodel.Node to the 642 // underlying Go type which may not be a datamodel.Node 643 typ, err := w.converter.customFromAny(basicNode) 644 if err != nil { 645 return err 646 } 647 w.parent.createNonPtrVal().Set(matchSettable(typ, reflect.ValueOf(basicNode))) 648 } else { 649 w.parent.createNonPtrVal().Set(reflect.ValueOf(basicNode)) 650 } 651 if w.parent.finish != nil { 652 if err := w.parent.finish(); err != nil { 653 return err 654 } 655 } 656 return nil 657 } 658 659 func (w *_assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) { 660 switch typ := w.schemaType.(type) { 661 case *schema.TypeAny: 662 basicBuilder := basicnode.Prototype.Any.NewBuilder() 663 mapAsm, err := basicBuilder.BeginMap(sizeHint) 664 if err != nil { 665 return nil, err 666 } 667 converter := w.cfg.converterFor(w.val) 668 return &basicMapAssembler{MapAssembler: mapAsm, builder: basicBuilder, parent: w, converter: converter}, nil 669 case *schema.TypeStruct: 670 val := w.createNonPtrVal() 671 // _structAssembler walks through the fields in order as the entries are 672 // assembled, verifyCompatibility() should mean it's safe to assume that 673 // they match the schema, but we need to keep track of the fields that are 674 // set in case of premature Finish() 675 doneFields := make([]bool, val.NumField()) 676 return &_structAssembler{ 677 cfg: w.cfg, 678 schemaType: typ, 679 val: val, 680 doneFields: doneFields, 681 finish: w.finish, 682 }, nil 683 case *schema.TypeMap: 684 // assume a struct{Keys []string, Values map[x]y} that we can fill with 685 // _mapAssembler 686 val := w.createNonPtrVal() 687 keysVal := val.FieldByName("Keys") 688 valuesVal := val.FieldByName("Values") 689 if valuesVal.IsNil() { 690 valuesVal.Set(reflect.MakeMap(valuesVal.Type())) 691 } 692 return &_mapAssembler{ 693 cfg: w.cfg, 694 schemaType: typ, 695 keysVal: keysVal, 696 valuesVal: valuesVal, 697 finish: w.finish, 698 }, nil 699 case *schema.TypeUnion: 700 // we can use _unionAssembler to assemble a union as if it were a map with 701 // a single entry 702 val := w.createNonPtrVal() 703 return &_unionAssembler{ 704 cfg: w.cfg, 705 schemaType: typ, 706 val: val, 707 finish: w.finish, 708 }, nil 709 } 710 return nil, datamodel.ErrWrongKind{ 711 TypeName: w.schemaType.Name(), 712 MethodName: "BeginMap", 713 AppropriateKind: datamodel.KindSet_JustMap, 714 ActualKind: actualKind(w.schemaType), 715 } 716 } 717 718 // basicListAssembler is for assembling basicnode values, it's only use is for 719 // Any fields that end up needing a BeginList() 720 type basicListAssembler struct { 721 datamodel.ListAssembler 722 723 builder datamodel.NodeBuilder 724 parent *_assembler 725 converter *converter 726 } 727 728 func (w *basicListAssembler) Finish() error { 729 if err := w.ListAssembler.Finish(); err != nil { 730 return err 731 } 732 basicNode := w.builder.Build() 733 if w.converter != nil { 734 // we can assume an Any converter because basicListAssembler is only for Any 735 // the user has registered the ability to convert a datamodel.Node to the 736 // underlying Go type which may not be a datamodel.Node 737 typ, err := w.converter.customFromAny(basicNode) 738 if err != nil { 739 return err 740 } 741 w.parent.createNonPtrVal().Set(matchSettable(typ, reflect.ValueOf(basicNode))) 742 } else { 743 w.parent.createNonPtrVal().Set(reflect.ValueOf(basicNode)) 744 } 745 if w.parent.finish != nil { 746 if err := w.parent.finish(); err != nil { 747 return err 748 } 749 } 750 return nil 751 } 752 753 func (w *_assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) { 754 switch typ := w.schemaType.(type) { 755 case *schema.TypeAny: 756 basicBuilder := basicnode.Prototype.Any.NewBuilder() 757 listAsm, err := basicBuilder.BeginList(sizeHint) 758 if err != nil { 759 return nil, err 760 } 761 converter := w.cfg.converterFor(w.val) 762 return &basicListAssembler{ListAssembler: listAsm, builder: basicBuilder, parent: w, converter: converter}, nil 763 case *schema.TypeList: 764 // we should be able to safely assume we're dealing with a Go slice here, 765 // so _listAssembler can append to that 766 val := w.createNonPtrVal() 767 return &_listAssembler{ 768 cfg: w.cfg, 769 schemaType: typ, 770 val: val, 771 finish: w.finish, 772 }, nil 773 } 774 return nil, datamodel.ErrWrongKind{ 775 TypeName: w.schemaType.Name(), 776 MethodName: "BeginList", 777 AppropriateKind: datamodel.KindSet_JustList, 778 ActualKind: actualKind(w.schemaType), 779 } 780 } 781 782 func (w *_assembler) AssignNull() error { 783 _, isAny := w.schemaType.(*schema.TypeAny) 784 if customConverter := w.cfg.converterFor(w.val); customConverter != nil && isAny { 785 // an Any field that is being assigned a Null, we pass the Null directly to 786 // the converter, regardless of whether this field is nullable or not 787 typ, err := customConverter.customFromAny(datamodel.Null) 788 if err != nil { 789 return err 790 } 791 w.createNonPtrVal().Set(matchSettable(typ, w.val)) 792 } else { 793 if !w.nullable { 794 return datamodel.ErrWrongKind{ 795 TypeName: w.schemaType.Name(), 796 MethodName: "AssignNull", 797 // TODO 798 } 799 } 800 // set the zero value for the underlying type as a stand-in for Null 801 w.val.Set(reflect.Zero(w.val.Type())) 802 } 803 if w.finish != nil { 804 if err := w.finish(); err != nil { 805 return err 806 } 807 } 808 return nil 809 } 810 811 func (w *_assembler) AssignBool(b bool) error { 812 if err := compatibleKind(w.schemaType, datamodel.Kind_Bool); err != nil { 813 return err 814 } 815 customConverter := w.cfg.converterFor(w.val) 816 _, isAny := w.schemaType.(*schema.TypeAny) 817 if customConverter != nil { 818 var typ interface{} 819 var err error 820 if isAny { 821 // field is an Any, so the converter will be an Any converter that wants 822 // a datamodel.Node to convert to whatever the underlying Go type is 823 if typ, err = customConverter.customFromAny(basicnode.NewBool(b)); err != nil { 824 return err 825 } 826 } else { 827 // field is a Bool, but the user has registered a converter from a bool to 828 // whatever the underlying Go type is 829 if typ, err = customConverter.customFromBool(b); err != nil { 830 return err 831 } 832 } 833 w.createNonPtrVal().Set(matchSettable(typ, w.val)) 834 } else { 835 if isAny { 836 // Any means the Go type must receive a datamodel.Node 837 w.createNonPtrVal().Set(reflect.ValueOf(basicnode.NewBool(b))) 838 } else { 839 w.createNonPtrVal().SetBool(b) 840 } 841 } 842 if w.finish != nil { 843 if err := w.finish(); err != nil { 844 return err 845 } 846 } 847 return nil 848 } 849 850 func (w *_assembler) assignUInt(uin datamodel.UintNode) error { 851 if err := compatibleKind(w.schemaType, datamodel.Kind_Int); err != nil { 852 return err 853 } 854 _, isAny := w.schemaType.(*schema.TypeAny) 855 // TODO: customConverter for uint?? 856 if isAny { 857 // Any means the Go type must receive a datamodel.Node 858 w.createNonPtrVal().Set(reflect.ValueOf(uin)) 859 } else { 860 i, err := uin.AsUint() 861 if err != nil { 862 return err 863 } 864 if kindUint[w.val.Kind()] { 865 w.createNonPtrVal().SetUint(i) 866 } else { 867 // TODO: check for overflow 868 w.createNonPtrVal().SetInt(int64(i)) 869 } 870 } 871 if w.finish != nil { 872 if err := w.finish(); err != nil { 873 return err 874 } 875 } 876 return nil 877 } 878 879 func (w *_assembler) AssignInt(i int64) error { 880 if err := compatibleKind(w.schemaType, datamodel.Kind_Int); err != nil { 881 return err 882 } 883 // TODO: check for overflow 884 customConverter := w.cfg.converterFor(w.val) 885 _, isAny := w.schemaType.(*schema.TypeAny) 886 if customConverter != nil { 887 var typ interface{} 888 var err error 889 if isAny { 890 // field is an Any, so the converter will be an Any converter that wants 891 // a datamodel.Node to convert to whatever the underlying Go type is 892 if typ, err = customConverter.customFromAny(basicnode.NewInt(i)); err != nil { 893 return err 894 } 895 } else { 896 // field is an Int, but the user has registered a converter from an int to 897 // whatever the underlying Go type is 898 if typ, err = customConverter.customFromInt(i); err != nil { 899 return err 900 } 901 } 902 w.createNonPtrVal().Set(matchSettable(typ, w.val)) 903 } else { 904 if isAny { 905 // Any means the Go type must receive a datamodel.Node 906 w.createNonPtrVal().Set(reflect.ValueOf(basicnode.NewInt(i))) 907 } else if kindUint[w.val.Kind()] { 908 if i < 0 { 909 // TODO: write a test 910 return fmt.Errorf("bindnode: cannot assign negative integer to %s", w.val.Type()) 911 } 912 w.createNonPtrVal().SetUint(uint64(i)) 913 } else { 914 w.createNonPtrVal().SetInt(i) 915 } 916 } 917 if w.finish != nil { 918 if err := w.finish(); err != nil { 919 return err 920 } 921 } 922 return nil 923 } 924 925 func (w *_assembler) AssignFloat(f float64) error { 926 if err := compatibleKind(w.schemaType, datamodel.Kind_Float); err != nil { 927 return err 928 } 929 customConverter := w.cfg.converterFor(w.val) 930 _, isAny := w.schemaType.(*schema.TypeAny) 931 if customConverter != nil { 932 var typ interface{} 933 var err error 934 if isAny { 935 // field is an Any, so the converter will be an Any converter that wants 936 // a datamodel.Node to convert to whatever the underlying Go type is 937 if typ, err = customConverter.customFromAny(basicnode.NewFloat(f)); err != nil { 938 return err 939 } 940 } else { 941 // field is a Float, but the user has registered a converter from a float 942 // to whatever the underlying Go type is 943 if typ, err = customConverter.customFromFloat(f); err != nil { 944 return err 945 } 946 } 947 w.createNonPtrVal().Set(matchSettable(typ, w.val)) 948 } else { 949 if isAny { 950 // Any means the Go type must receive a datamodel.Node 951 w.createNonPtrVal().Set(reflect.ValueOf(basicnode.NewFloat(f))) 952 } else { 953 w.createNonPtrVal().SetFloat(f) 954 } 955 } 956 if w.finish != nil { 957 if err := w.finish(); err != nil { 958 return err 959 } 960 } 961 return nil 962 } 963 964 func (w *_assembler) AssignString(s string) error { 965 if err := compatibleKind(w.schemaType, datamodel.Kind_String); err != nil { 966 return err 967 } 968 customConverter := w.cfg.converterFor(w.val) 969 _, isAny := w.schemaType.(*schema.TypeAny) 970 if customConverter != nil { 971 var typ interface{} 972 var err error 973 if isAny { 974 // field is an Any, so the converter will be an Any converter that wants 975 // a datamodel.Node to convert to whatever the underlying Go type is 976 if typ, err = customConverter.customFromAny(basicnode.NewString(s)); err != nil { 977 return err 978 } 979 } else { 980 // field is a String, but the user has registered a converter from a 981 // string to whatever the underlying Go type is 982 if typ, err = customConverter.customFromString(s); err != nil { 983 return err 984 } 985 } 986 w.createNonPtrVal().Set(matchSettable(typ, w.val)) 987 } else { 988 if isAny { 989 // Any means the Go type must receive a datamodel.Node 990 w.createNonPtrVal().Set(reflect.ValueOf(basicnode.NewString(s))) 991 } else { 992 w.createNonPtrVal().SetString(s) 993 } 994 } 995 if w.finish != nil { 996 if err := w.finish(); err != nil { 997 return err 998 } 999 } 1000 return nil 1001 } 1002 1003 func (w *_assembler) AssignBytes(p []byte) error { 1004 if err := compatibleKind(w.schemaType, datamodel.Kind_Bytes); err != nil { 1005 return err 1006 } 1007 customConverter := w.cfg.converterFor(w.val) 1008 _, isAny := w.schemaType.(*schema.TypeAny) 1009 if customConverter != nil { 1010 var typ interface{} 1011 var err error 1012 if isAny { 1013 // field is an Any, so the converter will be an Any converter that wants 1014 // a datamodel.Node to convert to whatever the underlying Go type is 1015 if typ, err = customConverter.customFromAny(basicnode.NewBytes(p)); err != nil { 1016 return err 1017 } 1018 } else { 1019 // field is a Bytes, but the user has registered a converter from a []byte 1020 // to whatever the underlying Go type is 1021 if typ, err = customConverter.customFromBytes(p); err != nil { 1022 return err 1023 } 1024 } 1025 w.createNonPtrVal().Set(matchSettable(typ, w.val)) 1026 } else { 1027 if isAny { 1028 // Any means the Go type must receive a datamodel.Node 1029 w.createNonPtrVal().Set(reflect.ValueOf(basicnode.NewBytes(p))) 1030 } else { 1031 w.createNonPtrVal().SetBytes(p) 1032 } 1033 } 1034 if w.finish != nil { 1035 if err := w.finish(); err != nil { 1036 return err 1037 } 1038 } 1039 return nil 1040 } 1041 1042 func (w *_assembler) AssignLink(link datamodel.Link) error { 1043 val := w.createNonPtrVal() 1044 // TODO: newVal.Type() panics if link==nil; add a test and fix. 1045 customConverter := w.cfg.converterFor(w.val) 1046 if _, ok := w.schemaType.(*schema.TypeAny); ok { 1047 if customConverter != nil { 1048 // field is an Any, so the converter will be an Any converter that wants 1049 // a datamodel.Node to convert to whatever the underlying Go type is 1050 typ, err := customConverter.customFromAny(basicnode.NewLink(link)) 1051 if err != nil { 1052 return err 1053 } 1054 w.createNonPtrVal().Set(matchSettable(typ, w.val)) 1055 } else { 1056 // Any means the Go type must receive a datamodel.Node 1057 val.Set(reflect.ValueOf(basicnode.NewLink(link))) 1058 } 1059 } else if customConverter != nil { 1060 if cl, ok := link.(cidlink.Link); ok { 1061 // field is a Link, but the user has registered a converter from a cid.Cid 1062 // to whatever the underlying Go type is 1063 typ, err := customConverter.customFromLink(cl.Cid) 1064 if err != nil { 1065 return err 1066 } 1067 w.createNonPtrVal().Set(matchSettable(typ, w.val)) 1068 } else { 1069 return fmt.Errorf("bindnode: custom converter can only receive a cidlink.Link through AssignLink") 1070 } 1071 } else if newVal := reflect.ValueOf(link); newVal.Type().AssignableTo(val.Type()) { 1072 // Directly assignable. 1073 val.Set(newVal) 1074 } else if newVal.Type() == goTypeCidLink && goTypeCid.AssignableTo(val.Type()) { 1075 // Unbox a cidlink.Link to assign to a go-cid.Cid value. 1076 newVal = newVal.FieldByName("Cid") 1077 val.Set(newVal) 1078 } else if actual := actualKind(w.schemaType); actual != datamodel.Kind_Link { 1079 // We're assigning a Link to a schema type that isn't a Link. 1080 return datamodel.ErrWrongKind{ 1081 TypeName: w.schemaType.Name(), 1082 MethodName: "AssignLink", 1083 AppropriateKind: datamodel.KindSet_JustLink, 1084 ActualKind: actualKind(w.schemaType), 1085 } 1086 } else { 1087 // The schema type is a Link, but we somehow can't assign to the Go value. 1088 // Almost certainly a bug; we should have verified for compatibility upfront. 1089 return fmt.Errorf("bindnode bug: AssignLink with %s argument can't be used on Go type %s", 1090 newVal.Type(), val.Type()) 1091 } 1092 if w.finish != nil { 1093 if err := w.finish(); err != nil { 1094 return err 1095 } 1096 } 1097 return nil 1098 } 1099 1100 func (w *_assembler) AssignNode(node datamodel.Node) error { 1101 // TODO: does this ever trigger? 1102 // newVal := reflect.ValueOf(node) 1103 // if newVal.Type().AssignableTo(w.val.Type()) { 1104 // w.val.Set(newVal) 1105 // return nil 1106 // } 1107 if uintNode, ok := node.(datamodel.UintNode); ok { 1108 return w.assignUInt(uintNode) 1109 } 1110 return datamodel.Copy(node, w) 1111 } 1112 1113 func (w *_assembler) Prototype() datamodel.NodePrototype { 1114 return &_prototype{cfg: w.cfg, schemaType: w.schemaType, goType: w.val.Type()} 1115 } 1116 1117 // _structAssembler is used for Struct assembling via BeginMap() 1118 type _structAssembler struct { 1119 // TODO: embed _assembler? 1120 1121 cfg config 1122 1123 schemaType *schema.TypeStruct 1124 val reflect.Value // non-pointer 1125 finish func() error 1126 1127 // TODO: more state checks 1128 1129 // TODO: Consider if we could do this in a cheaper way, 1130 // such as looking at the reflect.Value directly. 1131 // If not, at least avoid an extra alloc. 1132 doneFields []bool 1133 1134 // TODO: optimize for structs 1135 1136 curKey _assembler 1137 1138 nextIndex int // only used by repr.go 1139 } 1140 1141 func (w *_structAssembler) AssembleKey() datamodel.NodeAssembler { 1142 w.curKey = _assembler{ 1143 cfg: w.cfg, 1144 schemaType: schemaTypeString, 1145 val: reflect.New(goTypeString).Elem(), 1146 } 1147 return &w.curKey 1148 } 1149 1150 func (w *_structAssembler) AssembleValue() datamodel.NodeAssembler { 1151 // TODO: optimize this to do one lookup by name 1152 name := w.curKey.val.String() 1153 field := w.schemaType.Field(name) 1154 if field == nil { 1155 // TODO: should've been raised when the key was submitted instead. 1156 // TODO: should make well-typed errors for this. 1157 return _errorAssembler{fmt.Errorf("bindnode TODO: invalid key: %q is not a field in type %s", name, w.schemaType.Name())} 1158 // panic(schema.ErrInvalidKey{ 1159 // TypeName: w.schemaType.Name(), 1160 // Key: basicnode.NewString(name), 1161 // }) 1162 } 1163 ftyp, ok := w.val.Type().FieldByName(fieldNameFromSchema(name)) 1164 if !ok { 1165 // It is unfortunate this is not detected proactively earlier during bind. 1166 return _errorAssembler{fmt.Errorf("schema type %q has field %q, we expect go struct to have field %q", w.schemaType.Name(), field.Name(), fieldNameFromSchema(name))} 1167 } 1168 if len(ftyp.Index) > 1 { 1169 return _errorAssembler{fmt.Errorf("bindnode TODO: embedded fields")} 1170 } 1171 w.doneFields[ftyp.Index[0]] = true 1172 fval := w.val.FieldByIndex(ftyp.Index) 1173 if field.IsOptional() { 1174 if fval.Kind() == reflect.Ptr { 1175 // ptrVal = new(T); val = *ptrVal 1176 fval.Set(reflect.New(fval.Type().Elem())) 1177 fval = fval.Elem() 1178 } else { 1179 // val = *new(T) 1180 fval.Set(reflect.New(fval.Type()).Elem()) 1181 } 1182 } 1183 // TODO: reuse same assembler for perf? 1184 return &_assembler{ 1185 cfg: w.cfg, 1186 schemaType: field.Type(), 1187 val: fval, 1188 nullable: field.IsNullable(), 1189 } 1190 } 1191 1192 func (w *_structAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) { 1193 if err := w.AssembleKey().AssignString(k); err != nil { 1194 return nil, err 1195 } 1196 am := w.AssembleValue() 1197 return am, nil 1198 } 1199 1200 func (w *_structAssembler) Finish() error { 1201 fields := w.schemaType.Fields() 1202 var missing []string 1203 for i, field := range fields { 1204 if !field.IsOptional() && !w.doneFields[i] { 1205 missing = append(missing, field.Name()) 1206 } 1207 } 1208 if len(missing) > 0 { 1209 return schema.ErrMissingRequiredField{Missing: missing} 1210 } 1211 if w.finish != nil { 1212 if err := w.finish(); err != nil { 1213 return err 1214 } 1215 } 1216 return nil 1217 } 1218 1219 func (w *_structAssembler) KeyPrototype() datamodel.NodePrototype { 1220 // TODO: if the user provided their own schema with their own typesystem, 1221 // the schemaTypeString here may be using the wrong typesystem. 1222 return &_prototype{cfg: w.cfg, schemaType: schemaTypeString, goType: goTypeString} 1223 } 1224 1225 func (w *_structAssembler) ValuePrototype(k string) datamodel.NodePrototype { 1226 panic("bindnode TODO: struct ValuePrototype") 1227 } 1228 1229 type _errorAssembler struct { 1230 err error 1231 } 1232 1233 func (w _errorAssembler) BeginMap(int64) (datamodel.MapAssembler, error) { return nil, w.err } 1234 func (w _errorAssembler) BeginList(int64) (datamodel.ListAssembler, error) { return nil, w.err } 1235 func (w _errorAssembler) AssignNull() error { return w.err } 1236 func (w _errorAssembler) AssignBool(bool) error { return w.err } 1237 func (w _errorAssembler) AssignInt(int64) error { return w.err } 1238 func (w _errorAssembler) AssignFloat(float64) error { return w.err } 1239 func (w _errorAssembler) AssignString(string) error { return w.err } 1240 func (w _errorAssembler) AssignBytes([]byte) error { return w.err } 1241 func (w _errorAssembler) AssignLink(datamodel.Link) error { return w.err } 1242 func (w _errorAssembler) AssignNode(datamodel.Node) error { return w.err } 1243 func (w _errorAssembler) Prototype() datamodel.NodePrototype { return nil } 1244 1245 // used for Maps which we can assume are of type: struct{Keys []string, Values map[x]y}, 1246 // where we have Keys in keysVal and Values in valuesVal 1247 type _mapAssembler struct { 1248 cfg config 1249 schemaType *schema.TypeMap 1250 keysVal reflect.Value // non-pointer 1251 valuesVal reflect.Value // non-pointer 1252 finish func() error 1253 1254 // TODO: more state checks 1255 1256 curKey _assembler 1257 } 1258 1259 func (w *_mapAssembler) AssembleKey() datamodel.NodeAssembler { 1260 w.curKey = _assembler{ 1261 cfg: w.cfg, 1262 schemaType: w.schemaType.KeyType(), 1263 val: reflect.New(w.valuesVal.Type().Key()).Elem(), 1264 } 1265 return &w.curKey 1266 } 1267 1268 func (w *_mapAssembler) AssembleValue() datamodel.NodeAssembler { 1269 kval := w.curKey.val 1270 val := reflect.New(w.valuesVal.Type().Elem()).Elem() 1271 finish := func() error { 1272 // TODO: check for duplicates in keysVal 1273 w.keysVal.Set(reflect.Append(w.keysVal, kval)) 1274 1275 w.valuesVal.SetMapIndex(kval, val) 1276 return nil 1277 } 1278 return &_assembler{ 1279 cfg: w.cfg, 1280 schemaType: w.schemaType.ValueType(), 1281 val: val, 1282 nullable: w.schemaType.ValueIsNullable(), 1283 finish: finish, 1284 } 1285 } 1286 1287 func (w *_mapAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) { 1288 if err := w.AssembleKey().AssignString(k); err != nil { 1289 return nil, err 1290 } 1291 am := w.AssembleValue() 1292 return am, nil 1293 } 1294 1295 func (w *_mapAssembler) Finish() error { 1296 if w.finish != nil { 1297 if err := w.finish(); err != nil { 1298 return err 1299 } 1300 } 1301 return nil 1302 } 1303 1304 func (w *_mapAssembler) KeyPrototype() datamodel.NodePrototype { 1305 return &_prototype{cfg: w.cfg, schemaType: w.schemaType.KeyType(), goType: w.valuesVal.Type().Key()} 1306 } 1307 1308 func (w *_mapAssembler) ValuePrototype(k string) datamodel.NodePrototype { 1309 return &_prototype{cfg: w.cfg, schemaType: w.schemaType.ValueType(), goType: w.valuesVal.Type().Elem()} 1310 } 1311 1312 // _listAssembler is for operating directly on slices, which we have in val 1313 type _listAssembler struct { 1314 cfg config 1315 schemaType *schema.TypeList 1316 val reflect.Value // non-pointer 1317 finish func() error 1318 } 1319 1320 func (w *_listAssembler) AssembleValue() datamodel.NodeAssembler { 1321 goType := w.val.Type().Elem() 1322 // TODO: use a finish func to append 1323 w.val.Set(reflect.Append(w.val, reflect.New(goType).Elem())) 1324 return &_assembler{ 1325 cfg: w.cfg, 1326 schemaType: w.schemaType.ValueType(), 1327 val: w.val.Index(w.val.Len() - 1), 1328 nullable: w.schemaType.ValueIsNullable(), 1329 } 1330 } 1331 1332 func (w *_listAssembler) Finish() error { 1333 if w.finish != nil { 1334 if err := w.finish(); err != nil { 1335 return err 1336 } 1337 } 1338 return nil 1339 } 1340 1341 func (w *_listAssembler) ValuePrototype(idx int64) datamodel.NodePrototype { 1342 return &_prototype{cfg: w.cfg, schemaType: w.schemaType.ValueType(), goType: w.val.Type().Elem()} 1343 } 1344 1345 // when assembling as a Map but we anticipate a single value, which we need to 1346 // look up in the union members 1347 type _unionAssembler struct { 1348 cfg config 1349 schemaType *schema.TypeUnion 1350 val reflect.Value // non-pointer 1351 finish func() error 1352 1353 // TODO: more state checks 1354 1355 curKey _assembler 1356 } 1357 1358 func (w *_unionAssembler) AssembleKey() datamodel.NodeAssembler { 1359 w.curKey = _assembler{ 1360 cfg: w.cfg, 1361 schemaType: schemaTypeString, 1362 val: reflect.New(goTypeString).Elem(), 1363 } 1364 return &w.curKey 1365 } 1366 1367 func (w *_unionAssembler) AssembleValue() datamodel.NodeAssembler { 1368 name := w.curKey.val.String() 1369 var idx int 1370 var mtyp schema.Type 1371 for i, member := range w.schemaType.Members() { 1372 if member.Name() == name { 1373 idx = i 1374 mtyp = member 1375 break 1376 } 1377 } 1378 if mtyp == nil { 1379 return _errorAssembler{fmt.Errorf("bindnode TODO: missing member %s in %s", name, w.schemaType.Name())} 1380 // return nil, datamodel.ErrInvalidKey{ 1381 // TypeName: w.schemaType.Name(), 1382 // Key: basicnode.NewString(name), 1383 // } 1384 } 1385 1386 goType := w.val.Field(idx).Type().Elem() 1387 valPtr := reflect.New(goType) 1388 finish := func() error { 1389 unionSetMember(w.val, idx, valPtr) 1390 return nil 1391 } 1392 return &_assembler{ 1393 cfg: w.cfg, 1394 schemaType: mtyp, 1395 val: valPtr.Elem(), 1396 finish: finish, 1397 } 1398 } 1399 1400 func (w *_unionAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) { 1401 if err := w.AssembleKey().AssignString(k); err != nil { 1402 return nil, err 1403 } 1404 am := w.AssembleValue() 1405 return am, nil 1406 } 1407 1408 func (w *_unionAssembler) Finish() error { 1409 // TODO(rvagg): I think this might allow setting multiple members of the union 1410 // we need a test for this. 1411 haveIdx, _ := unionMember(w.val) 1412 if haveIdx < 0 { 1413 return schema.ErrNotUnionStructure{TypeName: w.schemaType.Name(), Detail: "a union must have exactly one entry"} 1414 } 1415 if w.finish != nil { 1416 if err := w.finish(); err != nil { 1417 return err 1418 } 1419 } 1420 return nil 1421 } 1422 1423 func (w *_unionAssembler) KeyPrototype() datamodel.NodePrototype { 1424 return &_prototype{cfg: w.cfg, schemaType: schemaTypeString, goType: goTypeString} 1425 } 1426 1427 func (w *_unionAssembler) ValuePrototype(k string) datamodel.NodePrototype { 1428 panic("bindnode TODO: union ValuePrototype") 1429 } 1430 1431 // _structIterator is for iterating over Struct types which operate over Go 1432 // structs. The iteration order is dictated by Go field declaration order which 1433 // should match the schema for this type. 1434 type _structIterator struct { 1435 // TODO: support embedded fields? 1436 cfg config 1437 1438 schemaType *schema.TypeStruct 1439 fields []schema.StructField 1440 val reflect.Value // non-pointer 1441 nextIndex int 1442 1443 // these are only used in repr.go 1444 reprEnd int 1445 } 1446 1447 func (w *_structIterator) Next() (key, value datamodel.Node, _ error) { 1448 if w.Done() { 1449 return nil, nil, datamodel.ErrIteratorOverread{} 1450 } 1451 field := w.fields[w.nextIndex] 1452 val := w.val.Field(w.nextIndex) 1453 w.nextIndex++ 1454 key = basicnode.NewString(field.Name()) 1455 if field.IsOptional() { 1456 if val.IsNil() { 1457 return key, datamodel.Absent, nil 1458 } 1459 if val.Kind() == reflect.Ptr { 1460 val = val.Elem() 1461 } 1462 } 1463 _, isAny := field.Type().(*schema.TypeAny) 1464 if isAny { 1465 if customConverter := w.cfg.converterFor(val); customConverter != nil { 1466 // field is an Any and we have an Any converter which takes the underlying 1467 // struct field value and returns a datamodel.Node 1468 v, err := customConverter.customToAny(ptrVal(val).Interface()) 1469 if err != nil { 1470 return nil, nil, err 1471 } 1472 return key, v, nil 1473 } 1474 } 1475 if field.IsNullable() { 1476 if val.IsNil() { 1477 return key, datamodel.Null, nil 1478 } 1479 if val.Kind() == reflect.Ptr { 1480 val = val.Elem() 1481 } 1482 } 1483 if isAny { 1484 // field holds a datamodel.Node 1485 return key, nonPtrVal(val).Interface().(datamodel.Node), nil 1486 } 1487 return key, newNode(w.cfg, field.Type(), val), nil 1488 } 1489 1490 func (w *_structIterator) Done() bool { 1491 return w.nextIndex >= len(w.fields) 1492 } 1493 1494 // _mapIterator is for iterating over a struct{Keys []string, Values map[x]y}, 1495 // where we have the Keys in keysVal and Values in valuesVal 1496 type _mapIterator struct { 1497 cfg config 1498 schemaType *schema.TypeMap 1499 keysVal reflect.Value // non-pointer 1500 valuesVal reflect.Value // non-pointer 1501 nextIndex int 1502 } 1503 1504 func (w *_mapIterator) Next() (key, value datamodel.Node, _ error) { 1505 if w.Done() { 1506 return nil, nil, datamodel.ErrIteratorOverread{} 1507 } 1508 goKey := w.keysVal.Index(w.nextIndex) 1509 val := w.valuesVal.MapIndex(goKey) 1510 w.nextIndex++ 1511 1512 key = newNode(w.cfg, w.schemaType.KeyType(), goKey) 1513 _, isAny := w.schemaType.ValueType().(*schema.TypeAny) 1514 if isAny { 1515 if customConverter := w.cfg.converterFor(val); customConverter != nil { 1516 // values of this map are Any and we have an Any converter which takes the 1517 // underlying map value and returns a datamodel.Node 1518 1519 // TODO(rvagg): can't call ptrVal on a map value that's not a pointer 1520 // so only map[string]*foo will work for the Values map and an Any 1521 // converter. Should we check in infer.go? 1522 val, err := customConverter.customToAny(ptrVal(val).Interface()) 1523 return key, val, err 1524 } 1525 } 1526 if w.schemaType.ValueIsNullable() { 1527 if val.IsNil() { 1528 return key, datamodel.Null, nil 1529 } 1530 val = val.Elem() // nullable entries are pointers 1531 } 1532 if isAny { 1533 // Values holds datamodel.Nodes 1534 return key, nonPtrVal(val).Interface().(datamodel.Node), nil 1535 } 1536 return key, newNode(w.cfg, w.schemaType.ValueType(), val), nil 1537 } 1538 1539 func (w *_mapIterator) Done() bool { 1540 return w.nextIndex >= w.keysVal.Len() 1541 } 1542 1543 // _listIterator is for iterating over slices, which is held in val 1544 type _listIterator struct { 1545 cfg config 1546 schemaType *schema.TypeList 1547 val reflect.Value // non-pointer 1548 nextIndex int 1549 } 1550 1551 func (w *_listIterator) Next() (index int64, value datamodel.Node, _ error) { 1552 if w.Done() { 1553 return 0, nil, datamodel.ErrIteratorOverread{} 1554 } 1555 idx := int64(w.nextIndex) 1556 val := w.val.Index(w.nextIndex) 1557 w.nextIndex++ 1558 if w.schemaType.ValueIsNullable() { 1559 if val.IsNil() { 1560 return idx, datamodel.Null, nil 1561 } 1562 val = val.Elem() // nullable values are pointers 1563 } 1564 if _, ok := w.schemaType.ValueType().(*schema.TypeAny); ok { 1565 if customConverter := w.cfg.converterFor(val); customConverter != nil { 1566 // values are Any and we have an Any converter which can take whatever 1567 // the underlying Go type in this slice is and return a datamodel.Node 1568 val, err := customConverter.customToAny(ptrVal(val).Interface()) 1569 return idx, val, err 1570 } 1571 // values are Any, assume that they are datamodel.Nodes 1572 return idx, nonPtrVal(val).Interface().(datamodel.Node), nil 1573 } 1574 return idx, newNode(w.cfg, w.schemaType.ValueType(), val), nil 1575 } 1576 1577 func (w *_listIterator) Done() bool { 1578 return w.nextIndex >= w.val.Len() 1579 } 1580 1581 type _unionIterator struct { 1582 // TODO: support embedded fields? 1583 cfg config 1584 schemaType *schema.TypeUnion 1585 members []schema.Type 1586 val reflect.Value // non-pointer 1587 1588 done bool 1589 } 1590 1591 func (w *_unionIterator) Next() (key, value datamodel.Node, _ error) { 1592 // we can only call this once for a union since a union can only have one 1593 // entry even though it behaves like a Map 1594 if w.Done() { 1595 return nil, nil, datamodel.ErrIteratorOverread{} 1596 } 1597 w.done = true 1598 1599 haveIdx, mval := unionMember(w.val) 1600 if haveIdx < 0 { 1601 return nil, nil, fmt.Errorf("bindnode: union %s has no member", w.val.Type()) 1602 } 1603 mtyp := w.members[haveIdx] 1604 1605 node := newNode(w.cfg, mtyp, mval) 1606 key = basicnode.NewString(mtyp.Name()) 1607 return key, node, nil 1608 } 1609 1610 func (w *_unionIterator) Done() bool { 1611 return w.done 1612 } 1613 1614 // --- uint64 special case handling 1615 1616 type _uintNode struct { 1617 cfg config 1618 schemaType schema.Type 1619 1620 val reflect.Value // non-pointer 1621 } 1622 1623 func (tu *_uintNode) Type() schema.Type { 1624 return tu.schemaType 1625 } 1626 func (tu *_uintNode) Representation() datamodel.Node { 1627 return (*_uintNodeRepr)(tu) 1628 } 1629 func (_uintNode) Kind() datamodel.Kind { 1630 return datamodel.Kind_Int 1631 } 1632 func (_uintNode) LookupByString(string) (datamodel.Node, error) { 1633 return mixins.Int{TypeName: "int"}.LookupByString("") 1634 } 1635 func (_uintNode) LookupByNode(key datamodel.Node) (datamodel.Node, error) { 1636 return mixins.Int{TypeName: "int"}.LookupByNode(nil) 1637 } 1638 func (_uintNode) LookupByIndex(idx int64) (datamodel.Node, error) { 1639 return mixins.Int{TypeName: "int"}.LookupByIndex(0) 1640 } 1641 func (_uintNode) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) { 1642 return mixins.Int{TypeName: "int"}.LookupBySegment(seg) 1643 } 1644 func (_uintNode) MapIterator() datamodel.MapIterator { 1645 return nil 1646 } 1647 func (_uintNode) ListIterator() datamodel.ListIterator { 1648 return nil 1649 } 1650 func (_uintNode) Length() int64 { 1651 return -1 1652 } 1653 func (_uintNode) IsAbsent() bool { 1654 return false 1655 } 1656 func (_uintNode) IsNull() bool { 1657 return false 1658 } 1659 func (_uintNode) AsBool() (bool, error) { 1660 return mixins.Int{TypeName: "int"}.AsBool() 1661 } 1662 func (tu *_uintNode) AsInt() (int64, error) { 1663 return (*_uintNodeRepr)(tu).AsInt() 1664 } 1665 func (tu *_uintNode) AsUint() (uint64, error) { 1666 return (*_uintNodeRepr)(tu).AsUint() 1667 } 1668 func (_uintNode) AsFloat() (float64, error) { 1669 return mixins.Int{TypeName: "int"}.AsFloat() 1670 } 1671 func (_uintNode) AsString() (string, error) { 1672 return mixins.Int{TypeName: "int"}.AsString() 1673 } 1674 func (_uintNode) AsBytes() ([]byte, error) { 1675 return mixins.Int{TypeName: "int"}.AsBytes() 1676 } 1677 func (_uintNode) AsLink() (datamodel.Link, error) { 1678 return mixins.Int{TypeName: "int"}.AsLink() 1679 } 1680 func (_uintNode) Prototype() datamodel.NodePrototype { 1681 return basicnode.Prototype__Int{} 1682 } 1683 1684 // we need this for _uintNode#Representation() so we don't return a TypeNode 1685 type _uintNodeRepr _uintNode 1686 1687 func (_uintNodeRepr) Kind() datamodel.Kind { 1688 return datamodel.Kind_Int 1689 } 1690 func (_uintNodeRepr) LookupByString(string) (datamodel.Node, error) { 1691 return mixins.Int{TypeName: "int"}.LookupByString("") 1692 } 1693 func (_uintNodeRepr) LookupByNode(key datamodel.Node) (datamodel.Node, error) { 1694 return mixins.Int{TypeName: "int"}.LookupByNode(nil) 1695 } 1696 func (_uintNodeRepr) LookupByIndex(idx int64) (datamodel.Node, error) { 1697 return mixins.Int{TypeName: "int"}.LookupByIndex(0) 1698 } 1699 func (_uintNodeRepr) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) { 1700 return mixins.Int{TypeName: "int"}.LookupBySegment(seg) 1701 } 1702 func (_uintNodeRepr) MapIterator() datamodel.MapIterator { 1703 return nil 1704 } 1705 func (_uintNodeRepr) ListIterator() datamodel.ListIterator { 1706 return nil 1707 } 1708 func (_uintNodeRepr) Length() int64 { 1709 return -1 1710 } 1711 func (_uintNodeRepr) IsAbsent() bool { 1712 return false 1713 } 1714 func (_uintNodeRepr) IsNull() bool { 1715 return false 1716 } 1717 func (_uintNodeRepr) AsBool() (bool, error) { 1718 return mixins.Int{TypeName: "int"}.AsBool() 1719 } 1720 func (tu *_uintNodeRepr) AsInt() (int64, error) { 1721 if err := compatibleKind(tu.schemaType, datamodel.Kind_Int); err != nil { 1722 return 0, err 1723 } 1724 if customConverter := tu.cfg.converterFor(tu.val); customConverter != nil { 1725 // user has registered a converter that takes the underlying type and returns an int 1726 return customConverter.customToInt(ptrVal(tu.val).Interface()) 1727 } 1728 val := nonPtrVal(tu.val) 1729 // we can assume it's a uint64 at this point 1730 u := val.Uint() 1731 if u > math.MaxInt64 { 1732 return 0, fmt.Errorf("bindnode: integer overflow, %d is too large for an int64", u) 1733 } 1734 return int64(u), nil 1735 } 1736 func (tu *_uintNodeRepr) AsUint() (uint64, error) { 1737 if err := compatibleKind(tu.schemaType, datamodel.Kind_Int); err != nil { 1738 return 0, err 1739 } 1740 // TODO(rvagg): do we want a converter option for uint values? do we combine it 1741 // with int converters? 1742 // we can assume it's a uint64 at this point 1743 return nonPtrVal(tu.val).Uint(), nil 1744 } 1745 func (_uintNodeRepr) AsFloat() (float64, error) { 1746 return mixins.Int{TypeName: "int"}.AsFloat() 1747 } 1748 func (_uintNodeRepr) AsString() (string, error) { 1749 return mixins.Int{TypeName: "int"}.AsString() 1750 } 1751 func (_uintNodeRepr) AsBytes() ([]byte, error) { 1752 return mixins.Int{TypeName: "int"}.AsBytes() 1753 } 1754 func (_uintNodeRepr) AsLink() (datamodel.Link, error) { 1755 return mixins.Int{TypeName: "int"}.AsLink() 1756 } 1757 func (_uintNodeRepr) Prototype() datamodel.NodePrototype { 1758 return basicnode.Prototype__Int{} 1759 }