 9bdcbe0447
			
		
	
	9bdcbe0447
	
	
	
		
			
			Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			508 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			508 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package bindnode
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"go/token"
 | |
| 	"reflect"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/ipfs/go-cid"
 | |
| 	"github.com/ipld/go-ipld-prime/datamodel"
 | |
| 	cidlink "github.com/ipld/go-ipld-prime/linking/cid"
 | |
| 	"github.com/ipld/go-ipld-prime/schema"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	goTypeBool    = reflect.TypeOf(false)
 | |
| 	goTypeInt     = reflect.TypeOf(int(0))
 | |
| 	goTypeFloat   = reflect.TypeOf(0.0)
 | |
| 	goTypeString  = reflect.TypeOf("")
 | |
| 	goTypeBytes   = reflect.TypeOf([]byte{})
 | |
| 	goTypeLink    = reflect.TypeOf((*datamodel.Link)(nil)).Elem()
 | |
| 	goTypeNode    = reflect.TypeOf((*datamodel.Node)(nil)).Elem()
 | |
| 	goTypeCidLink = reflect.TypeOf((*cidlink.Link)(nil)).Elem()
 | |
| 	goTypeCid     = reflect.TypeOf((*cid.Cid)(nil)).Elem()
 | |
| 
 | |
| 	schemaTypeBool   = schema.SpawnBool("Bool")
 | |
| 	schemaTypeInt    = schema.SpawnInt("Int")
 | |
| 	schemaTypeFloat  = schema.SpawnFloat("Float")
 | |
| 	schemaTypeString = schema.SpawnString("String")
 | |
| 	schemaTypeBytes  = schema.SpawnBytes("Bytes")
 | |
| 	schemaTypeLink   = schema.SpawnLink("Link")
 | |
| 	schemaTypeAny    = schema.SpawnAny("Any")
 | |
| )
 | |
| 
 | |
| // Consider exposing these APIs later, if they might be useful.
 | |
| 
 | |
| type seenEntry struct {
 | |
| 	goType     reflect.Type
 | |
| 	schemaType schema.Type
 | |
| }
 | |
| 
 | |
| // verifyCompatibility is the primary way we check that the schema type(s)
 | |
| // matches the Go type(s); so we do this before we can proceed operating on it.
 | |
| // verifyCompatibility doesn't return an error, it panics—the errors here are
 | |
| // not runtime errors, they're programmer errors because your schema doesn't
 | |
| // match your Go type
 | |
| func verifyCompatibility(cfg config, seen map[seenEntry]bool, goType reflect.Type, schemaType schema.Type) {
 | |
| 	// TODO(mvdan): support **T as well?
 | |
| 	if goType.Kind() == reflect.Ptr {
 | |
| 		goType = goType.Elem()
 | |
| 	}
 | |
| 
 | |
| 	// Avoid endless loops.
 | |
| 	//
 | |
| 	// TODO(mvdan): this is easy but fairly allocation-happy.
 | |
| 	// Plus, one map per call means we don't reuse work.
 | |
| 	if seen[seenEntry{goType, schemaType}] {
 | |
| 		return
 | |
| 	}
 | |
| 	seen[seenEntry{goType, schemaType}] = true
 | |
| 
 | |
| 	doPanic := func(format string, args ...interface{}) {
 | |
| 		panicFormat := "bindnode: schema type %s is not compatible with Go type %s"
 | |
| 		panicArgs := []interface{}{schemaType.Name(), goType.String()}
 | |
| 
 | |
| 		if format != "" {
 | |
| 			panicFormat += ": " + format
 | |
| 		}
 | |
| 		panicArgs = append(panicArgs, args...)
 | |
| 		panic(fmt.Sprintf(panicFormat, panicArgs...))
 | |
| 	}
 | |
| 	switch schemaType := schemaType.(type) {
 | |
| 	case *schema.TypeBool:
 | |
| 		if customConverter := cfg.converterForType(goType); customConverter != nil {
 | |
| 			if customConverter.kind != schema.TypeKind_Bool {
 | |
| 				doPanic("kind mismatch; custom converter for type is not for Bool")
 | |
| 			}
 | |
| 		} else if goType.Kind() != reflect.Bool {
 | |
| 			doPanic("kind mismatch; need boolean")
 | |
| 		}
 | |
| 	case *schema.TypeInt:
 | |
| 		if customConverter := cfg.converterForType(goType); customConverter != nil {
 | |
| 			if customConverter.kind != schema.TypeKind_Int {
 | |
| 				doPanic("kind mismatch; custom converter for type is not for Int")
 | |
| 			}
 | |
| 		} else if kind := goType.Kind(); !kindInt[kind] && !kindUint[kind] {
 | |
| 			doPanic("kind mismatch; need integer")
 | |
| 		}
 | |
| 	case *schema.TypeFloat:
 | |
| 		if customConverter := cfg.converterForType(goType); customConverter != nil {
 | |
| 			if customConverter.kind != schema.TypeKind_Float {
 | |
| 				doPanic("kind mismatch; custom converter for type is not for Float")
 | |
| 			}
 | |
| 		} else {
 | |
| 			switch goType.Kind() {
 | |
| 			case reflect.Float32, reflect.Float64:
 | |
| 			default:
 | |
| 				doPanic("kind mismatch; need float")
 | |
| 			}
 | |
| 		}
 | |
| 	case *schema.TypeString:
 | |
| 		// TODO: allow []byte?
 | |
| 		if customConverter := cfg.converterForType(goType); customConverter != nil {
 | |
| 			if customConverter.kind != schema.TypeKind_String {
 | |
| 				doPanic("kind mismatch; custom converter for type is not for String")
 | |
| 			}
 | |
| 		} else if goType.Kind() != reflect.String {
 | |
| 			doPanic("kind mismatch; need string")
 | |
| 		}
 | |
| 	case *schema.TypeBytes:
 | |
| 		// TODO: allow string?
 | |
| 		if customConverter := cfg.converterForType(goType); customConverter != nil {
 | |
| 			if customConverter.kind != schema.TypeKind_Bytes {
 | |
| 				doPanic("kind mismatch; custom converter for type is not for Bytes")
 | |
| 			}
 | |
| 		} else if goType.Kind() != reflect.Slice {
 | |
| 			doPanic("kind mismatch; need slice of bytes")
 | |
| 		} else if goType.Elem().Kind() != reflect.Uint8 {
 | |
| 			doPanic("kind mismatch; need slice of bytes")
 | |
| 		}
 | |
| 	case *schema.TypeEnum:
 | |
| 		if _, ok := schemaType.RepresentationStrategy().(schema.EnumRepresentation_Int); ok {
 | |
| 			if kind := goType.Kind(); kind != reflect.String && !kindInt[kind] && !kindUint[kind] {
 | |
| 				doPanic("kind mismatch; need string or integer")
 | |
| 			}
 | |
| 		} else {
 | |
| 			if goType.Kind() != reflect.String {
 | |
| 				doPanic("kind mismatch; need string")
 | |
| 			}
 | |
| 		}
 | |
| 	case *schema.TypeList:
 | |
| 		if goType.Kind() != reflect.Slice {
 | |
| 			doPanic("kind mismatch; need slice")
 | |
| 		}
 | |
| 		goType = goType.Elem()
 | |
| 		if schemaType.ValueIsNullable() {
 | |
| 			if ptr, nilable := ptrOrNilable(goType.Kind()); !nilable {
 | |
| 				doPanic("nullable types must be nilable")
 | |
| 			} else if ptr {
 | |
| 				goType = goType.Elem()
 | |
| 			}
 | |
| 		}
 | |
| 		verifyCompatibility(cfg, seen, goType, schemaType.ValueType())
 | |
| 	case *schema.TypeMap:
 | |
| 		//	struct {
 | |
| 		//		Keys   []K
 | |
| 		//		Values map[K]V
 | |
| 		//	}
 | |
| 		if goType.Kind() != reflect.Struct {
 | |
| 			doPanic("kind mismatch; need struct{Keys []K; Values map[K]V}")
 | |
| 		}
 | |
| 		if goType.NumField() != 2 {
 | |
| 			doPanic("%d vs 2 fields", goType.NumField())
 | |
| 		}
 | |
| 
 | |
| 		fieldKeys := goType.Field(0)
 | |
| 		if fieldKeys.Type.Kind() != reflect.Slice {
 | |
| 			doPanic("kind mismatch; need struct{Keys []K; Values map[K]V}")
 | |
| 		}
 | |
| 		verifyCompatibility(cfg, seen, fieldKeys.Type.Elem(), schemaType.KeyType())
 | |
| 
 | |
| 		fieldValues := goType.Field(1)
 | |
| 		if fieldValues.Type.Kind() != reflect.Map {
 | |
| 			doPanic("kind mismatch; need struct{Keys []K; Values map[K]V}")
 | |
| 		}
 | |
| 		keyType := fieldValues.Type.Key()
 | |
| 		verifyCompatibility(cfg, seen, keyType, schemaType.KeyType())
 | |
| 
 | |
| 		elemType := fieldValues.Type.Elem()
 | |
| 		if schemaType.ValueIsNullable() {
 | |
| 			if ptr, nilable := ptrOrNilable(elemType.Kind()); !nilable {
 | |
| 				doPanic("nullable types must be nilable")
 | |
| 			} else if ptr {
 | |
| 				elemType = elemType.Elem()
 | |
| 			}
 | |
| 		}
 | |
| 		verifyCompatibility(cfg, seen, elemType, schemaType.ValueType())
 | |
| 	case *schema.TypeStruct:
 | |
| 		if goType.Kind() != reflect.Struct {
 | |
| 			doPanic("kind mismatch; need struct")
 | |
| 		}
 | |
| 
 | |
| 		schemaFields := schemaType.Fields()
 | |
| 		if goType.NumField() != len(schemaFields) {
 | |
| 			doPanic("%d vs %d fields", goType.NumField(), len(schemaFields))
 | |
| 		}
 | |
| 		for i, schemaField := range schemaFields {
 | |
| 			schemaType := schemaField.Type()
 | |
| 			goType := goType.Field(i).Type
 | |
| 			switch {
 | |
| 			case schemaField.IsOptional() && schemaField.IsNullable():
 | |
| 				// TODO: https://github.com/ipld/go-ipld-prime/issues/340 will
 | |
| 				// help here, to avoid the double pointer. We can't use nilable
 | |
| 				// but non-pointer types because that's just one "nil" state.
 | |
| 				// TODO: deal with custom converters in this case
 | |
| 				if goType.Kind() != reflect.Ptr {
 | |
| 					doPanic("optional and nullable fields must use double pointers (**)")
 | |
| 				}
 | |
| 				goType = goType.Elem()
 | |
| 				if goType.Kind() != reflect.Ptr {
 | |
| 					doPanic("optional and nullable fields must use double pointers (**)")
 | |
| 				}
 | |
| 				goType = goType.Elem()
 | |
| 			case schemaField.IsOptional():
 | |
| 				if ptr, nilable := ptrOrNilable(goType.Kind()); !nilable {
 | |
| 					doPanic("optional fields must be nilable")
 | |
| 				} else if ptr {
 | |
| 					goType = goType.Elem()
 | |
| 				}
 | |
| 			case schemaField.IsNullable():
 | |
| 				if ptr, nilable := ptrOrNilable(goType.Kind()); !nilable {
 | |
| 					if customConverter := cfg.converterForType(goType); customConverter == nil {
 | |
| 						doPanic("nullable fields must be nilable")
 | |
| 					}
 | |
| 				} else if ptr {
 | |
| 					goType = goType.Elem()
 | |
| 				}
 | |
| 			}
 | |
| 			verifyCompatibility(cfg, seen, goType, schemaType)
 | |
| 		}
 | |
| 	case *schema.TypeUnion:
 | |
| 		if goType.Kind() != reflect.Struct {
 | |
| 			doPanic("kind mismatch; need struct for an union")
 | |
| 		}
 | |
| 
 | |
| 		schemaMembers := schemaType.Members()
 | |
| 		if goType.NumField() != len(schemaMembers) {
 | |
| 			doPanic("%d vs %d members", goType.NumField(), len(schemaMembers))
 | |
| 		}
 | |
| 
 | |
| 		for i, schemaType := range schemaMembers {
 | |
| 			goType := goType.Field(i).Type
 | |
| 			if ptr, nilable := ptrOrNilable(goType.Kind()); !nilable {
 | |
| 				doPanic("union members must be nilable")
 | |
| 			} else if ptr {
 | |
| 				goType = goType.Elem()
 | |
| 			}
 | |
| 			verifyCompatibility(cfg, seen, goType, schemaType)
 | |
| 		}
 | |
| 	case *schema.TypeLink:
 | |
| 		if customConverter := cfg.converterForType(goType); customConverter != nil {
 | |
| 			if customConverter.kind != schema.TypeKind_Link {
 | |
| 				doPanic("kind mismatch; custom converter for type is not for Link")
 | |
| 			}
 | |
| 		} else if goType != goTypeLink && goType != goTypeCidLink && goType != goTypeCid {
 | |
| 			doPanic("links in Go must be datamodel.Link, cidlink.Link, or cid.Cid")
 | |
| 		}
 | |
| 	case *schema.TypeAny:
 | |
| 		if customConverter := cfg.converterForType(goType); customConverter != nil {
 | |
| 			if customConverter.kind != schema.TypeKind_Any {
 | |
| 				doPanic("kind mismatch; custom converter for type is not for Any")
 | |
| 			}
 | |
| 		} else if goType != goTypeNode {
 | |
| 			doPanic("Any in Go must be datamodel.Node")
 | |
| 		}
 | |
| 	default:
 | |
| 		panic(fmt.Sprintf("%T", schemaType))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func ptrOrNilable(kind reflect.Kind) (ptr, nilable bool) {
 | |
| 	switch kind {
 | |
| 	case reflect.Ptr:
 | |
| 		return true, true
 | |
| 	case reflect.Interface, reflect.Map, reflect.Slice:
 | |
| 		return false, true
 | |
| 	default:
 | |
| 		return false, false
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // If we recurse past a large number of levels, we're mostly stuck in a loop.
 | |
| // Prevent burning CPU or causing OOM crashes.
 | |
| // If a user really wrote an IPLD schema or Go type with such deep nesting,
 | |
| // it's likely they are trying to abuse the system as well.
 | |
| const maxRecursionLevel = 1 << 10
 | |
| 
 | |
| type inferredStatus int
 | |
| 
 | |
| const (
 | |
| 	_ inferredStatus = iota
 | |
| 	inferringInProcess
 | |
| 	inferringDone
 | |
| )
 | |
| 
 | |
| // inferGoType can build a Go type given a schema
 | |
| func inferGoType(typ schema.Type, status map[schema.TypeName]inferredStatus, level int) reflect.Type {
 | |
| 	if level > maxRecursionLevel {
 | |
| 		panic(fmt.Sprintf("inferGoType: refusing to recurse past %d levels", maxRecursionLevel))
 | |
| 	}
 | |
| 	name := typ.Name()
 | |
| 	if status[name] == inferringInProcess {
 | |
| 		panic("bindnode: inferring Go types from cyclic schemas is not supported since Go reflection does not support creating named types")
 | |
| 	}
 | |
| 	status[name] = inferringInProcess
 | |
| 	defer func() { status[name] = inferringDone }()
 | |
| 	switch typ := typ.(type) {
 | |
| 	case *schema.TypeBool:
 | |
| 		return goTypeBool
 | |
| 	case *schema.TypeInt:
 | |
| 		return goTypeInt
 | |
| 	case *schema.TypeFloat:
 | |
| 		return goTypeFloat
 | |
| 	case *schema.TypeString:
 | |
| 		return goTypeString
 | |
| 	case *schema.TypeBytes:
 | |
| 		return goTypeBytes
 | |
| 	case *schema.TypeStruct:
 | |
| 		fields := typ.Fields()
 | |
| 		fieldsGo := make([]reflect.StructField, len(fields))
 | |
| 		for i, field := range fields {
 | |
| 			ftypGo := inferGoType(field.Type(), status, level+1)
 | |
| 			if field.IsNullable() {
 | |
| 				ftypGo = reflect.PtrTo(ftypGo)
 | |
| 			}
 | |
| 			if field.IsOptional() {
 | |
| 				ftypGo = reflect.PtrTo(ftypGo)
 | |
| 			}
 | |
| 			fieldsGo[i] = reflect.StructField{
 | |
| 				Name: fieldNameFromSchema(field.Name()),
 | |
| 				Type: ftypGo,
 | |
| 			}
 | |
| 		}
 | |
| 		return reflect.StructOf(fieldsGo)
 | |
| 	case *schema.TypeMap:
 | |
| 		ktyp := inferGoType(typ.KeyType(), status, level+1)
 | |
| 		vtyp := inferGoType(typ.ValueType(), status, level+1)
 | |
| 		if typ.ValueIsNullable() {
 | |
| 			vtyp = reflect.PtrTo(vtyp)
 | |
| 		}
 | |
| 		// We need an extra field to keep the map ordered,
 | |
| 		// since IPLD maps must have stable iteration order.
 | |
| 		// We could sort when iterating, but that's expensive.
 | |
| 		// Keeping the insertion order is easy and intuitive.
 | |
| 		//
 | |
| 		//	struct {
 | |
| 		//		Keys   []K
 | |
| 		//		Values map[K]V
 | |
| 		//	}
 | |
| 		fieldsGo := []reflect.StructField{
 | |
| 			{
 | |
| 				Name: "Keys",
 | |
| 				Type: reflect.SliceOf(ktyp),
 | |
| 			},
 | |
| 			{
 | |
| 				Name: "Values",
 | |
| 				Type: reflect.MapOf(ktyp, vtyp),
 | |
| 			},
 | |
| 		}
 | |
| 		return reflect.StructOf(fieldsGo)
 | |
| 	case *schema.TypeList:
 | |
| 		etyp := inferGoType(typ.ValueType(), status, level+1)
 | |
| 		if typ.ValueIsNullable() {
 | |
| 			etyp = reflect.PtrTo(etyp)
 | |
| 		}
 | |
| 		return reflect.SliceOf(etyp)
 | |
| 	case *schema.TypeUnion:
 | |
| 		// type goUnion struct {
 | |
| 		// 	Type1 *Type1
 | |
| 		// 	Type2 *Type2
 | |
| 		// 	...
 | |
| 		// }
 | |
| 		members := typ.Members()
 | |
| 		fieldsGo := make([]reflect.StructField, len(members))
 | |
| 		for i, ftyp := range members {
 | |
| 			ftypGo := inferGoType(ftyp, status, level+1)
 | |
| 			fieldsGo[i] = reflect.StructField{
 | |
| 				Name: fieldNameFromSchema(ftyp.Name()),
 | |
| 				Type: reflect.PtrTo(ftypGo),
 | |
| 			}
 | |
| 		}
 | |
| 		return reflect.StructOf(fieldsGo)
 | |
| 	case *schema.TypeLink:
 | |
| 		return goTypeLink
 | |
| 	case *schema.TypeEnum:
 | |
| 		// TODO: generate int for int reprs by default?
 | |
| 		return goTypeString
 | |
| 	case *schema.TypeAny:
 | |
| 		return goTypeNode
 | |
| 	case nil:
 | |
| 		panic("bindnode: unexpected nil schema.Type")
 | |
| 	}
 | |
| 	panic(fmt.Sprintf("%T", typ))
 | |
| }
 | |
| 
 | |
| // from IPLD Schema field names like "foo" to Go field names like "Foo".
 | |
| func fieldNameFromSchema(name string) string {
 | |
| 	fieldName := strings.Title(name) //lint:ignore SA1019 cases.Title doesn't work for this
 | |
| 	if !token.IsIdentifier(fieldName) {
 | |
| 		panic(fmt.Sprintf("bindnode: inferred field name %q is not a valid Go identifier", fieldName))
 | |
| 	}
 | |
| 	return fieldName
 | |
| }
 | |
| 
 | |
| var defaultTypeSystem schema.TypeSystem
 | |
| 
 | |
| func init() {
 | |
| 	defaultTypeSystem.Init()
 | |
| 
 | |
| 	defaultTypeSystem.Accumulate(schemaTypeBool)
 | |
| 	defaultTypeSystem.Accumulate(schemaTypeInt)
 | |
| 	defaultTypeSystem.Accumulate(schemaTypeFloat)
 | |
| 	defaultTypeSystem.Accumulate(schemaTypeString)
 | |
| 	defaultTypeSystem.Accumulate(schemaTypeBytes)
 | |
| 	defaultTypeSystem.Accumulate(schemaTypeLink)
 | |
| 	defaultTypeSystem.Accumulate(schemaTypeAny)
 | |
| }
 | |
| 
 | |
| // TODO: support IPLD maps and unions in inferSchema
 | |
| 
 | |
| // TODO: support bringing your own TypeSystem?
 | |
| 
 | |
| // TODO: we should probably avoid re-spawning the same types if the TypeSystem
 | |
| // has them, and test that that works as expected
 | |
| 
 | |
| // inferSchema can build a schema from a Go type
 | |
| func inferSchema(typ reflect.Type, level int) schema.Type {
 | |
| 	if level > maxRecursionLevel {
 | |
| 		panic(fmt.Sprintf("inferSchema: refusing to recurse past %d levels", maxRecursionLevel))
 | |
| 	}
 | |
| 	switch typ.Kind() {
 | |
| 	case reflect.Bool:
 | |
| 		return schemaTypeBool
 | |
| 	case reflect.Int64:
 | |
| 		return schemaTypeInt
 | |
| 	case reflect.Float64:
 | |
| 		return schemaTypeFloat
 | |
| 	case reflect.String:
 | |
| 		return schemaTypeString
 | |
| 	case reflect.Struct:
 | |
| 		// these types must match exactly since we need symmetry of being able to
 | |
| 		// get the values an also assign values to them
 | |
| 		if typ == goTypeCid || typ == goTypeCidLink {
 | |
| 			return schemaTypeLink
 | |
| 		}
 | |
| 
 | |
| 		fieldsSchema := make([]schema.StructField, typ.NumField())
 | |
| 		for i := range fieldsSchema {
 | |
| 			field := typ.Field(i)
 | |
| 			ftyp := field.Type
 | |
| 			ftypSchema := inferSchema(ftyp, level+1)
 | |
| 			fieldsSchema[i] = schema.SpawnStructField(
 | |
| 				field.Name, // TODO: allow configuring the name with tags
 | |
| 				ftypSchema.Name(),
 | |
| 
 | |
| 				// TODO: support nullable/optional with tags
 | |
| 				false,
 | |
| 				false,
 | |
| 			)
 | |
| 		}
 | |
| 		name := typ.Name()
 | |
| 		if name == "" {
 | |
| 			panic("TODO: anonymous composite types")
 | |
| 		}
 | |
| 		typSchema := schema.SpawnStruct(name, fieldsSchema, nil)
 | |
| 		defaultTypeSystem.Accumulate(typSchema)
 | |
| 		return typSchema
 | |
| 	case reflect.Slice:
 | |
| 		if typ.Elem().Kind() == reflect.Uint8 {
 | |
| 			// Special case for []byte.
 | |
| 			return schemaTypeBytes
 | |
| 		}
 | |
| 
 | |
| 		nullable := false
 | |
| 		if typ.Elem().Kind() == reflect.Ptr {
 | |
| 			nullable = true
 | |
| 		}
 | |
| 		etypSchema := inferSchema(typ.Elem(), level+1)
 | |
| 		name := typ.Name()
 | |
| 		if name == "" {
 | |
| 			name = "List_" + etypSchema.Name()
 | |
| 		}
 | |
| 		typSchema := schema.SpawnList(name, etypSchema.Name(), nullable)
 | |
| 		defaultTypeSystem.Accumulate(typSchema)
 | |
| 		return typSchema
 | |
| 	case reflect.Interface:
 | |
| 		// these types must match exactly since we need symmetry of being able to
 | |
| 		// get the values an also assign values to them
 | |
| 		if typ == goTypeLink {
 | |
| 			return schemaTypeLink
 | |
| 		}
 | |
| 		if typ == goTypeNode {
 | |
| 			return schemaTypeAny
 | |
| 		}
 | |
| 		panic("bindnode: unable to infer from interface")
 | |
| 	}
 | |
| 	panic(fmt.Sprintf("bindnode: unable to infer from type %s", typ.Kind().String()))
 | |
| }
 | |
| 
 | |
| // There are currently 27 reflect.Kind iota values,
 | |
| // so 32 should be plenty to ensure we don't panic in practice.
 | |
| 
 | |
| var kindInt = [32]bool{
 | |
| 	reflect.Int:   true,
 | |
| 	reflect.Int8:  true,
 | |
| 	reflect.Int16: true,
 | |
| 	reflect.Int32: true,
 | |
| 	reflect.Int64: true,
 | |
| }
 | |
| 
 | |
| var kindUint = [32]bool{
 | |
| 	reflect.Uint:   true,
 | |
| 	reflect.Uint8:  true,
 | |
| 	reflect.Uint16: true,
 | |
| 	reflect.Uint32: true,
 | |
| 	reflect.Uint64: true,
 | |
| }
 |