infer.go 2.13 KB
Newer Older
1 2 3 4 5 6 7
package bindnode

import (
	"fmt"
	"reflect"
	"strings"

tavit ohanian's avatar
tavit ohanian committed
8
	"gitlab.dms3.io/ld/go-ld-prime/schema"
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
)

// Consider exposing these APIs later, if they might be useful.

func inferGoType(typ schema.Type) reflect.Type {
	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()
		goFields := make([]reflect.StructField, len(fields))
		for i, field := range fields {
			ftyp := inferGoType(field.Type())
			if field.IsNullable() {
				ftyp = reflect.PtrTo(ftyp)
			}
			if field.IsOptional() {
				ftyp = reflect.PtrTo(ftyp)
			}
			goFields[i] = reflect.StructField{
				Name: fieldNameFromSchema(field.Name()),
				Type: ftyp,
			}
		}
		return reflect.StructOf(goFields)
	case *schema.TypeMap:
		ktyp := inferGoType(typ.KeyType())
		vtyp := inferGoType(typ.ValueType())
		if typ.ValueIsNullable() {
			vtyp = reflect.PtrTo(vtyp)
		}
		// We need an extra field to keep the map ordered,
49
		// since LD maps must have stable iteration order.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
		// We could sort when iterating, but that's expensive.
		// Keeping the insertion order is easy and intuitive.
		//
		//	struct {
		//		Keys   []K
		//		Values map[K]V
		//	}
		goFields := []reflect.StructField{
			{
				Name: "Keys",
				Type: reflect.SliceOf(ktyp),
			},
			{
				Name: "Values",
				Type: reflect.MapOf(ktyp, vtyp),
			},
		}
		return reflect.StructOf(goFields)
	case *schema.TypeList:
		etyp := inferGoType(typ.ValueType())
		if typ.ValueIsNullable() {
			etyp = reflect.PtrTo(etyp)
		}
		return reflect.SliceOf(etyp)
	case *schema.TypeUnion:
		// We need an extra field to record what member we stored.
		type goUnion struct {
			Index int // 0..len(typ.Members)-1
			Value interface{}
		}
		return reflect.TypeOf(goUnion{})
	}
	panic(fmt.Sprintf("%T\n", typ))
}

85
// from LD Schema field names like "foo" to Go field names like "Foo".
86 87 88 89 90 91 92
func fieldNameFromSchema(name string) string {
	return strings.Title(name)
}

func inferSchema(typ reflect.Type) schema.Type {
	panic("TODO")
}