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  }