func typeIsOrContainsVerbotenImpl(t reflect.Type, verboten reflect.Kind) bool { switch t.Kind() { case verboten: return true case reflect.Map: if typeIsOrContainsVerbotenLocked(t.Key(), verboten) || typeIsOrContainsVerbotenLocked(t.Elem(), verboten) { return true } case reflect.Array, reflect.Ptr, reflect.Slice: if typeIsOrContainsVerbotenLocked(t.Elem(), verboten) { return true } case reflect.Struct: for i := 0; i < t.NumField(); i++ { if typeIsOrContainsVerbotenLocked(t.Field(i).Type, verboten) { return true } } case reflect.Chan, reflect.Func, reflect.Interface: // Not strictly correct, but cloning these kinds is not allowed. return true } return false }
// verifyHandler ensures that the given t is a function with the following signature: // func(json.Context, *ArgType)(*ResType, error) func verifyHandler(t reflect.Type) error { if t.NumIn() != 2 || t.NumOut() != 2 { return fmt.Errorf("handler should be of format func(json.Context, *ArgType) (*ResType, error)") } isStructPtr := func(t reflect.Type) bool { return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct } isMap := func(t reflect.Type) bool { return t.Kind() == reflect.Map && t.Key().Kind() == reflect.String } validateArgRes := func(t reflect.Type, name string) error { if !isStructPtr(t) && !isMap(t) { return fmt.Errorf("%v should be a pointer to a struct, or a map[string]interface{}", name) } return nil } if t.In(0) != typeOfContext { return fmt.Errorf("arg0 should be of type json.Context") } if err := validateArgRes(t.In(1), "second argument"); err != nil { return err } if err := validateArgRes(t.Out(0), "first return value"); err != nil { return err } if !t.Out(1).AssignableTo(typeOfError) { return fmt.Errorf("second return value should be an error") } return nil }
func getOrCreateSchema(definitions Definitions, t reflect.Type) *Schema { var result Schema if t.Kind() == reflect.Ptr { t = t.Elem() } if t.Kind() == reflect.Map { if t.Key().Kind() != reflect.String { panic("swagger supports only maps with string keys") } result.Type = "object" result.AdditionalProperties = getOrCreateSchema(definitions, t.Elem()) return &result } if t.Kind() == reflect.Interface { result.Type = "object" return &result } result.Type = typeName(t) if result.Type == "object" { name := t.String() if _, ok := definitions[name]; ok { result = Schema{Ref: "#/definitions/" + name} return &result } definitions[name] = result if t.NumField() > 0 { result.Properties = Properties{} } for i := 0; i < t.NumField(); i++ { field := t.Field(i) if field.PkgPath != "" { continue } name := field.Tag.Get("json") if name == "" { name = field.Tag.Get("key") if name == "" { name = field.Name } } if field.Type.Kind() != reflect.Ptr { result.Required = append(result.Required, name) } fieldSchema := getOrCreateSchema(definitions, field.Type) fieldSchema.Description = field.Tag.Get("description") result.Properties[name] = fieldSchema } definitions[name] = result result = Schema{Ref: "#/definitions/" + name} } else if result.Type == "array" { itemsSchema := getOrCreateSchema(definitions, t.Elem()) result.Items = &Items{*itemsSchema} } return &result }
func copyTableToMap(L *lua.State, t reflect.Type, idx int, visited map[uintptr]interface{}) interface{} { if t == nil { t = tmap } te, tk := t.Elem(), t.Key() m := reflect.MakeMap(t) // See copyTableToSlice. ptr := L.ToPointer(idx) if !luaIsEmpty(L, idx) { visited[ptr] = m.Interface() } L.PushNil() if idx < 0 { idx-- } for L.Next(idx) != 0 { // key at -2, value at -1 key := reflect.ValueOf(luaToGo(L, tk, -2, visited)) val := reflect.ValueOf(luaToGo(L, te, -1, visited)) if val.Interface() == nullv.Interface() { val = reflect.Zero(te) } m.SetMapIndex(key, val) L.Pop(1) } return m.Interface() }
// Add all necessary imports for the type, recursing as appropriate. func addImportsForType(imports importMap, t reflect.Type) { // Add any import needed for the type itself. addImportForType(imports, t) // Handle special cases where recursion is needed. switch t.Kind() { case reflect.Array, reflect.Chan, reflect.Ptr, reflect.Slice: addImportsForType(imports, t.Elem()) case reflect.Func: // Input parameters. for i := 0; i < t.NumIn(); i++ { addImportsForType(imports, t.In(i)) } // Return values. for i := 0; i < t.NumOut(); i++ { addImportsForType(imports, t.Out(i)) } case reflect.Map: addImportsForType(imports, t.Key()) addImportsForType(imports, t.Elem()) } }
func (g *conversionGenerator) typeName(inType reflect.Type) string { switch inType.Kind() { case reflect.Map: return fmt.Sprintf("map[%s]%s", g.typeName(inType.Key()), g.typeName(inType.Elem())) case reflect.Slice: return fmt.Sprintf("[]%s", g.typeName(inType.Elem())) case reflect.Ptr: return fmt.Sprintf("*%s", g.typeName(inType.Elem())) default: typeWithPkg := fmt.Sprintf("%s", inType) slices := strings.Split(typeWithPkg, ".") if len(slices) == 1 { // Default package. return slices[0] } if len(slices) == 2 { pkg := slices[0] if val, found := g.pkgOverwrites[pkg]; found { pkg = val } if pkg != "" { pkg = pkg + "." } return pkg + slices[1] } panic("Incorrect type name: " + typeWithPkg) } }
func newMapEncoder(t reflect.Type) encoderFunc { if t.Key().Kind() != reflect.String && !t.Key().Implements(textMarshalerType) { return unsupportedTypeEncoder } me := &mapEncoder{typeEncoder(t.Elem())} return me.encode }
func evalCompositeLitMap(ctx *Ctx, t reflect.Type, lit *CompositeLit, env *Env) (reflect.Value, error) { m := reflect.MakeMap(t) kT := knownType{t.Key()} vT := knownType{t.Elem()} for _, elt := range lit.Elts { kv := elt.(*KeyValueExpr) k, err := evalTypedExpr(ctx, kv.Key.(Expr), kT, env) if err != nil { return reflect.Value{}, err } if kT[0].Kind() == reflect.Interface { dynamicT := k[0].Elem().Type() if !isStaticTypeComparable(dynamicT) { return reflect.Value{}, PanicUnhashableType{dynamicT} } } v, err := evalTypedExpr(ctx, kv.Value.(Expr), vT, env) if err != nil { return reflect.Value{}, err } m.SetMapIndex(k[0], v[0]) } return m, nil }
func (g *conversionGenerator) typeName(inType reflect.Type) string { switch inType.Kind() { case reflect.Slice: return fmt.Sprintf("[]%s", g.typeName(inType.Elem())) case reflect.Ptr: return fmt.Sprintf("*%s", g.typeName(inType.Elem())) case reflect.Map: if len(inType.Name()) == 0 { return fmt.Sprintf("map[%s]%s", g.typeName(inType.Key()), g.typeName(inType.Elem())) } fallthrough default: pkg, name := inType.PkgPath(), inType.Name() if len(name) == 0 && inType.Kind() == reflect.Struct { return "struct{}" } if len(pkg) == 0 { // Default package. return name } if val, found := g.pkgOverwrites[pkg]; found { pkg = val } if len(pkg) == 0 { return name } short := g.addImportByPath(pkg) if len(short) > 0 { return fmt.Sprintf("%s.%s", short, name) } return name } }
// mapEncodeScratch returns a new reflect.Value matching the map's value type, // and a structPointer suitable for passing to an encoder or sizer. func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { // Prepare addressable doubly-indirect placeholders for the key and value types. // This is needed because the element-type encoders expect **T, but the map iteration produces T. keycopy = reflect.New(mapType.Key()).Elem() // addressable K keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K keyptr.Set(keycopy.Addr()) // keybase = toStructPointer(keyptr.Addr()) // **K // Value types are more varied and require special handling. switch mapType.Elem().Kind() { case reflect.Slice: // []byte var dummy []byte valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte valbase = toStructPointer(valcopy.Addr()) case reflect.Ptr: // message; the generated field type is map[K]*Msg (so V is *Msg), // so we only need one level of indirection. valcopy = reflect.New(mapType.Elem()).Elem() // addressable V valbase = toStructPointer(valcopy.Addr()) default: // everything else valcopy = reflect.New(mapType.Elem()).Elem() // addressable V valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V valptr.Set(valcopy.Addr()) // valbase = toStructPointer(valptr.Addr()) // **V } return }
func newMapEncoder(t reflect.Type, vx reflect.Value) encoderFunc { if t.Key().Kind() != reflect.String { return unsupportedTypeEncoder } me := &mapEncoder{typeEncoder(vx.Type().Elem(), reflect.Value{})} return me.encode }
// unify attempts to satisfy a pair of types, where the `param` type is the // expected type of a function argument and the `input` type is the known // type of a function argument. The `param` type may be parametric (that is, // it may contain a type that is convertible to TypeVariable) but the // `input` type may *not* be parametric. // // Any failure to unify the two types results in a panic. // // The end result of unification is a type environment: a set of substitutions // from type variable to a Go type. func (tp typePair) unify(param, input reflect.Type) error { if tyname := tyvarName(input); len(tyname) > 0 { return tp.error("Type variables are not allowed in the types of " + "arguments.") } if tyname := tyvarName(param); len(tyname) > 0 { if cur, ok := tp.tyenv[tyname]; ok && cur != input { return tp.error("Type variable %s expected type '%s' but got '%s'.", tyname, cur, input) } else if !ok { tp.tyenv[tyname] = input } return nil } if param.Kind() != input.Kind() { return tp.error("Cannot unify different kinds of types '%s' and '%s'.", param, input) } switch param.Kind() { case reflect.Array: return tp.unify(param.Elem(), input.Elem()) case reflect.Chan: if param.ChanDir() != input.ChanDir() { return tp.error("Cannot unify '%s' with '%s' "+ "(channel directions are different: '%s' != '%s').", param, input, param.ChanDir(), input.ChanDir()) } return tp.unify(param.Elem(), input.Elem()) case reflect.Func: if param.NumIn() != input.NumIn() || param.NumOut() != input.NumOut() { return tp.error("Cannot unify '%s' with '%s'.", param, input) } for i := 0; i < param.NumIn(); i++ { if err := tp.unify(param.In(i), input.In(i)); err != nil { return err } } for i := 0; i < param.NumOut(); i++ { if err := tp.unify(param.Out(i), input.Out(i)); err != nil { return err } } case reflect.Map: if err := tp.unify(param.Key(), input.Key()); err != nil { return err } return tp.unify(param.Elem(), input.Elem()) case reflect.Ptr: return tp.unify(param.Elem(), input.Elem()) case reflect.Slice: return tp.unify(param.Elem(), input.Elem()) } // The only other container types are Interface and Struct. // I am unsure about what to do with interfaces. Mind is fuzzy. // Structs? I don't think it really makes much sense to use type // variables inside of them. return nil }
// tysubst attempts to substitute all type variables within a single return // type with their corresponding Go type from the type environment. // // tysubst will panic if a type variable is unbound, or if it encounters a // type that cannot be dynamically created. Such types include arrays, // functions and structs. (A limitation of the `reflect` package.) func (rt returnType) tysubst(typ reflect.Type) reflect.Type { if tyname := tyvarName(typ); len(tyname) > 0 { if thetype, ok := rt.tyenv[tyname]; !ok { rt.panic("Unbound type variable %s.", tyname) } else { return thetype } } switch typ.Kind() { case reflect.Array: rt.panic("Cannot dynamically create Array types.") case reflect.Chan: return reflect.ChanOf(typ.ChanDir(), rt.tysubst(typ.Elem())) case reflect.Func: rt.panic("Cannot dynamically create Function types.") case reflect.Interface: rt.panic("TODO") case reflect.Map: return reflect.MapOf(rt.tysubst(typ.Key()), rt.tysubst(typ.Elem())) case reflect.Ptr: return reflect.PtrTo(rt.tysubst(typ.Elem())) case reflect.Slice: return reflect.SliceOf(rt.tysubst(typ.Elem())) case reflect.Struct: rt.panic("Cannot dynamically create Struct types.") case reflect.UnsafePointer: rt.panic("Cannot dynamically create unsafe.Pointer types.") } // We've covered all the composite types, so we're only left with // base types. return typ }
func compileField(typ reflect.Type, name string, args []parse.Node, final reflect.Type) (fn lookupFn, elem reflect.Type) { if isNilType(typ) { fn = compileFieldDynamic(name, args) return } if m, exist := typ.MethodByName(name); exist { fn = compileMethodCall(typ, m.Func, args, final) elem = m.Type.Out(0) return } switch typ.Kind() { case reflect.Struct: structField, found := typ.FieldByName(name) if !found { panic(fmt.Errorf("%s has no field %s", typ, name)) } fn = func(s state, v reflect.Value, final interface{}) reflect.Value { return v.FieldByIndex(structField.Index) } elem = structField.Type return case reflect.Map: k := reflect.ValueOf(name) fn = func(s state, v reflect.Value, final interface{}) reflect.Value { return v.MapIndex(k) } elem = typ.Key() return } panic(fmt.Errorf("struct or map expected, but got %s", typ)) }
func newMapEncoder(t reflect.Type) encoderFunc { if t.Key().Kind() != reflect.String { return unsupportedTypeEncoder } me := &mapEncoder{typeEncoder(t.Elem())} return me.encode }
// getSignature returns the signature of the given type and panics on unknown types. func getSignature(t reflect.Type) string { // handle simple types first switch t.Kind() { case reflect.Uint8: return "y" case reflect.Bool: return "b" case reflect.Int16: return "n" case reflect.Uint16: return "q" case reflect.Int32: if t == unixFDType { return "h" } return "i" case reflect.Uint32: if t == unixFDIndexType { return "h" } return "u" case reflect.Int64: return "x" case reflect.Uint64: return "t" case reflect.Float64: return "d" case reflect.Ptr: return getSignature(t.Elem()) case reflect.String: if t == objectPathType { return "o" } return "s" case reflect.Struct: if t == variantType { return "v" } else if t == signatureType { return "g" } var s string for i := 0; i < t.NumField(); i++ { field := t.Field(i) if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { s += getSignature(t.Field(i).Type) } } return "(" + s + ")" case reflect.Array, reflect.Slice: return "a" + getSignature(t.Elem()) case reflect.Map: if !isKeyType(t.Key()) { panic(InvalidTypeError{t}) } return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}" case reflect.Interface: return "v" } panic(InvalidTypeError{t}) }
func checkCompositeLitMap(ctx *Ctx, lit *CompositeLit, t reflect.Type, env *Env) (*CompositeLit, []error) { var errs, moreErrs []error kT := t.Key() // Don't check for duplicate interface{} keys. This is a gc bug // http://code.google.com/p/go/issues/detail?id=7214 var seen map[interface{}]bool if kT.Kind() != reflect.Interface { seen = make(map[interface{}]bool, len(lit.Elts)) } eltT := t.Elem() for i := range lit.Elts { if kv, ok := lit.Elts[i].(*ast.KeyValueExpr); !ok { lit.Elts[i], moreErrs = CheckExpr(ctx, lit.Elts[i], env) if moreErrs != nil { errs = append(errs, moreErrs...) } errs = append(errs, ErrMissingMapKey{at(ctx, lit.Elts[i])}) } else { lit.Elts[i] = &KeyValueExpr{KeyValueExpr: kv} k, ok, moreErrs := checkExprAssignableTo(ctx, kv.Key, kT, env) if !ok { if len(k.KnownType()) != 0 { kF := fakeCheckExpr(kv.Key, env) kF.setKnownType(knownType(k.KnownType())) errs = append(errs, ErrBadMapKey{at(ctx, kF), kT}) } } else { errs = append(errs, moreErrs...) } kv.Key = k if seen != nil && k.IsConst() { var constKey interface{} if k.KnownType()[0] == ConstNil { constKey = nil } else if cT, ok := k.KnownType()[0].(ConstType); ok { c, _ := promoteConstToTyped(ctx, cT, constValue(k.Const()), cT.DefaultPromotion(), k) constKey = reflect.Value(c).Interface() } else { constKey = k.Const().Interface() } if seen[constKey] { errs = append(errs, ErrDuplicateMapKey{at(ctx, kv.Key)}) } seen[constKey] = true } v, moreErrs := checkMapValue(ctx, kv.Value, eltT, env) if moreErrs != nil { errs = append(errs, moreErrs...) } kv.Value = v } } return lit, errs }
// Return the string that should be used to refer to the supplied type within // the given package. The output is not guaranteed to be pretty, and should be // run through a tool like gofmt afterward. // // For example, a pointer to an io.Reader may be rendered as "*Reader" or // "*io.Reader" depending on whether the package path is "io" or not. func typeString( t reflect.Type, pkgPath string) (s string) { // Is this type named? If so we use its name, possibly with a package prefix. // // Examples: // // int // string // error // gcs.Bucket // if t.Name() != "" { if t.PkgPath() == pkgPath { s = t.Name() } else { s = t.String() } return } // This type is unnamed. Recurse. switch t.Kind() { case reflect.Array: s = fmt.Sprintf("[%d]%s", t.Len(), typeString(t.Elem(), pkgPath)) case reflect.Chan: s = fmt.Sprintf("%s %s", t.ChanDir(), typeString(t.Elem(), pkgPath)) case reflect.Func: s = typeString_Func(t, pkgPath) case reflect.Interface: s = typeString_Interface(t, pkgPath) case reflect.Map: s = fmt.Sprintf( "map[%s]%s", typeString(t.Key(), pkgPath), typeString(t.Elem(), pkgPath)) case reflect.Ptr: s = fmt.Sprintf("*%s", typeString(t.Elem(), pkgPath)) case reflect.Slice: s = fmt.Sprintf("[]%s", typeString(t.Elem(), pkgPath)) case reflect.Struct: s = typeString_Struct(t, pkgPath) default: log.Panicf("Unhandled kind %v for type: %v", t.Kind(), t) } return }
func validateType(t reflect.Type) (err error) { t = removePtr(t) for _, vd := range validatedTypes { if vd.t == t { return *vd.err } } validatedTypes = append(validatedTypes, &validatedType{ t: t, err: &err, }) switch t.Kind() { case reflect.Chan, reflect.Func, reflect.Interface, reflect.UnsafePointer: err = fmt.Errorf("%s. Found [%s]", t.Kind(), t) return err case reflect.Array, reflect.Slice: if err = validateType(t.Elem()); err != nil { err = fmt.Errorf("%s in the %s [%s]", err, t.Kind(), t) return err } case reflect.Map: if err = validateType(t.Elem()); err != nil { err = fmt.Errorf("%s in the value of map [%s]", err, t) return err } if err = validateType(t.Key()); err != nil { err = fmt.Errorf("%s in the key of map [%s]", err, t) return err } case reflect.Struct: if supportsGob(t) { return nil } // Special case for struct{} if t.NumField() == 0 { return nil } n := 0 for i := 0; i < t.NumField(); i++ { f := t.Field(i) if f.PkgPath == "" { if err = validateType(f.Type); err != nil { err = fmt.Errorf("%s in the field [%s] of struct [%s]", err, f.Name, t) return err } n++ } } if n == 0 { err = fmt.Errorf("struct without exported fields [%s]", t) return err } } return err }
// baseMapKind returns the the Kind of the key and value types of a map. If // the map consists of other maps, the Kind of the key of the lowest level map // will be returned; e.g. reflect.String and reflect.Int will be returned for // map[string]map[int]string. func baseMapKind(typ reflect.Type) (k, v reflect.Kind) { if typ.Kind() == reflect.Ptr { return baseMapKind(typ.Elem()) } k = typ.Key().Kind() if k == reflect.Ptr { k, _ = baseKind(typ.Key()) } v, _ = baseKind(typ.Elem()) return k, v }
func tryAndSortMapKeys(mt reflect.Type, k []reflect.Value) { // Try our stock sortable values. switch mt.Key().Kind() { case reflect.String, reflect.Int: vs := &sortableValueSlice{ kind: mt.Key().Kind(), elements: k, } sort.Sort(vs) } }
func getMapValue(ic *Inception, name string, typ reflect.Type, ptr bool, forceString bool) string { var out = "" if typ.Key().Kind() != reflect.String { out += fmt.Sprintf("/* Falling back. type=%v kind=%v */\n", typ, typ.Kind()) out += ic.q.Flush() out += "err = buf.Encode(" + name + ")" + "\n" out += "if err != nil {" + "\n" out += " return err" + "\n" out += "}" + "\n" return out } var elemKind reflect.Kind elemKind = typ.Elem().Kind() switch elemKind { case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.Bool: ic.OutputImports[`fflib "github.com/pquerna/ffjson/fflib/v1"`] = true out += "if " + name + " == nil {" + "\n" ic.q.Write("null") out += ic.q.GetQueued() ic.q.DeleteLast() out += "} else {" + "\n" out += ic.q.WriteFlush("{ ") out += " for key, value := range " + name + " {" + "\n" out += " fflib.WriteJsonString(buf, key)" + "\n" out += " buf.WriteString(`:`)" + "\n" out += getGetInnerValue(ic, "value", typ.Elem(), false, forceString) out += " buf.WriteByte(',')" + "\n" out += " }" + "\n" out += "buf.Rewind(1)" + "\n" out += ic.q.WriteFlush("}") out += "}" + "\n" default: out += ic.q.Flush() out += fmt.Sprintf("/* Falling back. type=%v kind=%v */\n", typ, typ.Kind()) out += "err = buf.Encode(" + name + ")" + "\n" out += "if err != nil {" + "\n" out += " return err" + "\n" out += "}" + "\n" } return out }
func newMapEncoder(t reflect.Type) encoderFunc { switch t.Key().Kind() { case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: default: if !t.Key().Implements(textMarshalerType) { return unsupportedTypeEncoder } } me := &mapEncoder{typeEncoder(t.Elem())} return me.encode }
func (g *conversionGenerator) generateConversionsForMap(inType, outType reflect.Type) error { inKey := inType.Key() outKey := outType.Key() if err := g.generateConversionsBetween(inKey, outKey); err != nil { return err } inValue := inType.Elem() outValue := outType.Elem() if err := g.generateConversionsBetween(inValue, outValue); err != nil { return err } return nil }
func ValType(t reflect.Type) (decl string) { switch k := t.Kind(); k { case reflect.Struct: decl = "struct {\n" for i, ed := 0, t.NumField(); i < ed; i++ { ft := t.Field(i) if ft.Tag != "-" || ft.Tag.Get("goval") == "-" { s := ft.Name + " " + ValType(ft.Type) if ft.Tag != "" { s += " `" + strings.Replace("`", "\\`", string(ft.Tag), -1) + "`" } decl += indent(s) + "\n" } } decl += "}" case reflect.Array: decl = "[" + strconv.Itoa(t.Len()) + "]" + Val(t.Elem()) case reflect.Slice: decl = "[]" + Val(t.Elem()) case reflect.Chan: switch t.ChanDir() { case reflect.RecvDir: decl = "<-chan " case reflect.SendDir: decl = "chan<- " case reflect.BothDir: decl = "chan " default: panic("Didn't expect a dir other than send, recieve or both.") } decl += Val(t.Elem()) case reflect.Map: decl = "map[" + ValType(t.Key()) + "]" + ValType(t.Elem()) case reflect.Ptr: decl = "*" + ValType(t.Elem()) case reflect.Interface: decl = "interface {\n" for i, ed := 0, t.NumMethod(); i < ed; i++ { ft := t.Method(i) s := ft.Name + FormatFuncArguments(ft.Type) decl += indent(s) + "\n" } decl += "}" case reflect.Func: decl = "func" + FormatFuncArguments(t) default: return k.String() } return }
func typeSchema(title string, t reflect.Type, tag reflect.StructTag) *Value { fieldType := fieldType(t, tag) isReadOnly := tag.Get("readOnly") != "" value := &Value{ Title: title, Type: fieldType, Required: isRequired(tag), Enum: enum(tag), Description: tag.Get("description"), Format: Format(tag.Get("format")), ReadOnly: isReadOnly, } switch fieldType { case Map: value.Title = t.Name() value.Format = "tabs" // map items value.Items = &Value{ Type: Object, HeaderTemplate: "{{self.key}}", Properties: map[string]*Value{ "key": typeSchema("key", t.Key(), reflect.StructTag("")), "value": typeSchema("value", t.Elem(), reflect.StructTag("")), }, } // the enum annotation for maps is for the key not for the map itself value.Items.Properties["key"].Enum = enum(tag) value.Enum = make([]string, 0) // if there is valueEnum then the value is considered enum if tag.Get("valueEnum") != "" { value.Items.Properties["value"].Enum = strings.Split(tag.Get("valueEnum"), ",") } else { value.Items.Properties["value"].Enum = make([]string, 0) } case Array: value.Items = typeSchema(t.Name(), t.Elem(), tag) value.Items.HeaderTemplate = tag.Get("headerTemplate") case ProtoEnum: value.Enum = getProtoEnumValues(t) case Object: value = structSchema(title, t, tag) } return value }
func getTypes(t reflect.Type, s supportingTypes, c *int) *Type { n, p := t.String(), t.PkgPath() if _, ok := t.MethodByName("MarshalJSON"); ok { return custom(n, p) } switch t.Kind() { case reflect.String: return simple(String) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return simple(Int) case reflect.Float32, reflect.Float64: return simple(Float) case reflect.Bool: return simple(Bool) case reflect.Ptr: return s.set(n, p, func() *Type { return ptrOf(getTypes(t.Elem(), s, c)) }) case reflect.Array, reflect.Slice: if t.Elem().Kind() == reflect.Uint8 { return simple(Bytes) } return s.set(n, p, func() *Type { return arrayOf(getTypes(t.Elem(), s, c)) }) case reflect.Struct: if p == "" { // gets an anonymous type name and fake the package n = anonTypeName(c) p = "github.com/shutej/go2flow/anonymous" } return s.set(n, p, func() *Type { return structOf(getFields(t, s, c)) }) case reflect.Map: if t.Key().Kind() != reflect.String { log.Fatalf("unexpected map key type: %v", t.Key()) } return s.set(n, p, func() *Type { return mapOf(getTypes(t.Elem(), s, c)) }) } log.Fatalf("unknown kind for type: %v", t) return nil }
func (t *TGen) genMap(name string, val reflect.Type) { t.src += "// map encode\n" t.genNilBegin(name) t.genUint32("uint32(len(" + name + "))") tmpKey := t.tmpNameGen.Get() // get tmp var name tmpVal := t.tmpNameGen.Get() // get tmp var name t.src += "for " + tmpKey + ", " + tmpVal + " := range " + name + " {\n" t.stackName.Push(tmpKey) t.encode(val.Key()) t.stackName.Push(tmpVal) t.encode(val.Elem()) t.src += "}\n" t.genNilEnd() }
func getDecoder(typ reflect.Type) decoderFunc { kind := typ.Kind() // Addressable struct field value. if kind != reflect.Ptr && reflect.PtrTo(typ).Implements(decoderType) { return decodeCustomValuePtr } if typ.Implements(decoderType) { return decodeCustomValue } if typ.Implements(unmarshalerType) { return unmarshalValue } if decoder, ok := typDecMap[typ]; ok { return decoder } switch kind { case reflect.Ptr: return ptrDecoderFunc(typ) case reflect.Slice: elem := typ.Elem() switch elem.Kind() { case reflect.Uint8: return decodeBytesValue } switch elem { case stringType: return decodeStringSliceValue } case reflect.Array: if typ.Elem().Kind() == reflect.Uint8 { return decodeByteArrayValue } case reflect.Map: if typ.Key() == stringType { switch typ.Elem() { case stringType: return decodeMapStringStringValue case interfaceType: return decodeMapStringInterfaceValue } } } return valueDecoders[kind] }
// decodeMap decodes a map and stores it in value. // Maps are encoded as a length followed by key:value pairs. // Because the internals of maps are not visible to us, we must // use reflection rather than pointer magic. func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value reflect.Value, keyOp, elemOp decOp, ovfl error) { if value.IsNil() { // Allocate map. value.Set(reflect.MakeMap(mtyp)) } n := int(state.decodeUint()) keyIsPtr := mtyp.Key().Kind() == reflect.Ptr elemIsPtr := mtyp.Elem().Kind() == reflect.Ptr for i := 0; i < n; i++ { key := decodeIntoValue(state, keyOp, keyIsPtr, allocValue(mtyp.Key()), ovfl) elem := decodeIntoValue(state, elemOp, elemIsPtr, allocValue(mtyp.Elem()), ovfl) value.SetMapIndex(key, elem) } }