gorgonia.org/gorgonia@v0.9.17/formatter.go (about) 1 package gorgonia 2 3 import ( 4 "bytes" 5 "fmt" 6 "reflect" 7 ) 8 9 type mapFmt struct { 10 m reflect.Value // map 11 } 12 13 // FmtNodeMap is a convenience function to print map[*Node]<T> 14 // 15 // The fmt flag that makes it all nicely formatted is "-". Because a map consists of two types (key's type 16 // and val's type), and the Go fmt verb doesn't quite allow us to do something like "%ds", a hack is introduced 17 // to enable nicer printing of map[*Node]<T> 18 // 19 // Here's the hack: 20 // The "#" flag is used to indicate if the map will use the Node's ID or Name when formatting the map. 21 // %-v nodeName:%v 22 // %-#v nodeID:%v 23 // %-d nodeName:%x 24 // %-#d nodeID: %x 25 // %-p nodeName:%p 26 // %-#p nodeID:%p 27 // 28 // If the "-" flag is not found, then the formatter returns the default Go format for map[<T>]<T2> 29 func FmtNodeMap(m interface{}) mapFmt { 30 refVal := reflect.ValueOf(m) 31 if refVal.Kind() != reflect.Map { 32 panic("Only expect maps in FmtNodeMap") 33 } 34 35 t := refVal.Type() 36 keyType := t.Key() 37 38 var n *Node 39 if keyType != reflect.TypeOf(n) { 40 panic("Only expected map[*Node]<T>") 41 } 42 43 return mapFmt{ 44 m: refVal, 45 } 46 } 47 48 func (mf mapFmt) defaultFmt(s fmt.State, c rune) { 49 var buf bytes.Buffer 50 buf.WriteRune('%') 51 for i := 0; i < 128; i++ { 52 if s.Flag(i) { 53 buf.WriteByte(byte(i)) 54 } 55 } 56 if w, ok := s.Width(); ok { 57 fmt.Fprintf(&buf, "%d", w) 58 } 59 if p, ok := s.Precision(); ok { 60 fmt.Fprintf(&buf, ".%d", p) 61 } 62 buf.WriteRune(c) 63 fmt.Fprintf(s, buf.String(), mf.m) 64 } 65 66 func (mf mapFmt) format(s fmt.State, c rune) string { 67 var tmpl string 68 switch { 69 case c == 'v': 70 if s.Flag('#') { 71 tmpl = "\t%x: %v\n" 72 } else { 73 tmpl = "\t%s: %v\n" 74 } 75 case c == 'd': 76 if s.Flag('#') { 77 tmpl = "\t%x: %x\n" 78 } else { 79 tmpl = "\t%s: %x\n" 80 } 81 case c == 'p': 82 if s.Flag('#') { 83 tmpl = "\t%x: %p\n" 84 } else { 85 tmpl = "\t%s: %p\n" 86 } 87 default: 88 tmpl = "\t%s: %s\n" 89 } 90 return tmpl 91 } 92 93 func (mf mapFmt) Format(s fmt.State, c rune) { 94 refVal := mf.m 95 var n *Node 96 t := refVal.Type() 97 keyType := t.Key() 98 if keyType != reflect.TypeOf(n) { 99 panic("Only map[*Node]<T> is expected") 100 } 101 102 tmpl := mf.format(s, c) 103 104 keys := refVal.MapKeys() 105 if s.Flag('-') { 106 if s.Flag('#') { 107 // then key, will try its best to be a number 108 109 fmt.Fprintf(s, "map[Node.ID]%s {\n", t.Elem()) 110 for i := 0; i < refVal.Len(); i++ { 111 key := keys[i] 112 val := refVal.MapIndex(key) 113 114 meth := key.MethodByName("ID") 115 id := meth.Call(nil)[0] 116 117 valType := val.Type() 118 if valType == reflect.TypeOf(n) { 119 switch c { 120 case 'd': 121 valMeth := val.MethodByName("ID") 122 valID := valMeth.Call(nil)[0] 123 fmt.Fprintf(s, tmpl, id, valID) 124 default: 125 strMeth := val.MethodByName("String") 126 str := strMeth.Call(nil)[0] 127 fmt.Fprintf(s, tmpl, id, str) 128 129 } 130 } else { 131 if _, ok := valType.MethodByName("Format"); ok { 132 fmt.Fprintf(s, "\t%x: ", id) 133 fmtMeth := val.MethodByName("Format") 134 fmtMeth.Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(c)}) 135 fmt.Fprintf(s, "\n") 136 } else if _, ok := valType.MethodByName("String"); ok { 137 strMeth := val.MethodByName("String") 138 str := strMeth.Call(nil)[0] 139 fmt.Fprintf(s, tmpl, id, str) 140 } else { 141 fmt.Fprintf(s, tmpl, id, val) 142 } 143 } 144 } 145 s.Write([]byte("}")) 146 147 } else { 148 fmt.Fprintf(s, "map[Node.Name]%s {\n", t.Elem()) 149 for i := 0; i < refVal.Len(); i++ { 150 key := keys[i] 151 val := refVal.MapIndex(key) 152 153 meth := key.MethodByName("String") 154 id := meth.Call(nil)[0] 155 156 valType := val.Type() 157 if valType == reflect.TypeOf(n) { 158 switch c { 159 case 'd': 160 valMeth := val.MethodByName("ID") 161 valID := valMeth.Call(nil)[0] 162 fmt.Fprintf(s, tmpl, id, valID) 163 default: 164 strMeth := val.MethodByName("String") 165 str := strMeth.Call(nil)[0] 166 fmt.Fprintf(s, tmpl, id, str) 167 168 } 169 } else { 170 if _, ok := valType.MethodByName("Format"); ok { 171 fmt.Fprintf(s, "\t%s: ", id) 172 fmtMeth := val.MethodByName("Format") 173 fmtMeth.Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(c)}) 174 fmt.Fprintf(s, "\n") 175 } else if _, ok := valType.MethodByName("String"); ok { 176 strMeth := val.MethodByName("String") 177 str := strMeth.Call(nil)[0] 178 fmt.Fprintf(s, tmpl, id, str) 179 } else { 180 fmt.Fprintf(s, tmpl, id, val) 181 } 182 } 183 } 184 s.Write([]byte("}")) 185 } 186 return 187 } 188 mf.defaultFmt(s, c) 189 }