github.com/sld880311/docker@v0.0.0-20200524143708-d5593973a475/cli/command/formatter/reflect.go (about) 1 package formatter 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "reflect" 7 "unicode" 8 ) 9 10 func marshalJSON(x interface{}) ([]byte, error) { 11 m, err := marshalMap(x) 12 if err != nil { 13 return nil, err 14 } 15 return json.Marshal(m) 16 } 17 18 // marshalMap marshals x to map[string]interface{} 19 func marshalMap(x interface{}) (map[string]interface{}, error) { 20 val := reflect.ValueOf(x) 21 if val.Kind() != reflect.Ptr { 22 return nil, fmt.Errorf("expected a pointer to a struct, got %v", val.Kind()) 23 } 24 if val.IsNil() { 25 return nil, fmt.Errorf("expxected a pointer to a struct, got nil pointer") 26 } 27 valElem := val.Elem() 28 if valElem.Kind() != reflect.Struct { 29 return nil, fmt.Errorf("expected a pointer to a struct, got a pointer to %v", valElem.Kind()) 30 } 31 typ := val.Type() 32 m := make(map[string]interface{}) 33 for i := 0; i < val.NumMethod(); i++ { 34 k, v, err := marshalForMethod(typ.Method(i), val.Method(i)) 35 if err != nil { 36 return nil, err 37 } 38 if k != "" { 39 m[k] = v 40 } 41 } 42 return m, nil 43 } 44 45 var unmarshallableNames = map[string]struct{}{"FullHeader": {}} 46 47 // marshalForMethod returns the map key and the map value for marshalling the method. 48 // It returns ("", nil, nil) for valid but non-marshallable parameter. (e.g. "unexportedFunc()") 49 func marshalForMethod(typ reflect.Method, val reflect.Value) (string, interface{}, error) { 50 if val.Kind() != reflect.Func { 51 return "", nil, fmt.Errorf("expected func, got %v", val.Kind()) 52 } 53 name, numIn, numOut := typ.Name, val.Type().NumIn(), val.Type().NumOut() 54 _, blackListed := unmarshallableNames[name] 55 // FIXME: In text/template, (numOut == 2) is marshallable, 56 // if the type of the second param is error. 57 marshallable := unicode.IsUpper(rune(name[0])) && !blackListed && 58 numIn == 0 && numOut == 1 59 if !marshallable { 60 return "", nil, nil 61 } 62 result := val.Call(make([]reflect.Value, numIn)) 63 intf := result[0].Interface() 64 return name, intf, nil 65 }