func: Implement TextMarshaler for map keys
Tim Hockin
2 years ago
35 | 35 |
|
36 | 36 |
import (
|
37 | 37 |
"bytes"
|
|
38 |
"encoding"
|
38 | 39 |
"fmt"
|
39 | 40 |
"path/filepath"
|
40 | 41 |
"reflect"
|
|
491 | 492 |
if i > 0 {
|
492 | 493 |
buf.WriteByte(',')
|
493 | 494 |
}
|
494 | |
// prettyWithFlags will produce already-escaped values
|
495 | |
keystr := f.prettyWithFlags(it.Key().Interface(), 0)
|
496 | |
if t.Key().Kind() != reflect.String {
|
497 | |
// JSON only does string keys. Unlike Go's standard JSON, we'll
|
498 | |
// convert just about anything to a string.
|
|
495 |
// If a map key supports TextMarshaler, use it.
|
|
496 |
keystr := ""
|
|
497 |
if m, ok := it.Key().Interface().(encoding.TextMarshaler); ok {
|
|
498 |
txt, err := m.MarshalText()
|
|
499 |
if err != nil {
|
|
500 |
keystr = fmt.Sprintf("<error-MarshalText: %s>", err.Error())
|
|
501 |
} else {
|
|
502 |
keystr = string(txt)
|
|
503 |
}
|
499 | 504 |
keystr = prettyString(keystr)
|
|
505 |
} else {
|
|
506 |
// prettyWithFlags will produce already-escaped values
|
|
507 |
keystr = f.prettyWithFlags(it.Key().Interface(), 0)
|
|
508 |
if t.Key().Kind() != reflect.String {
|
|
509 |
// JSON only does string keys. Unlike Go's standard JSON, we'll
|
|
510 |
// convert just about anything to a string.
|
|
511 |
keystr = prettyString(keystr)
|
|
512 |
}
|
500 | 513 |
}
|
501 | 514 |
buf.WriteString(keystr)
|
502 | 515 |
buf.WriteByte(':')
|
34 | 34 |
}
|
35 | 35 |
func ptrstr(s string) *string {
|
36 | 36 |
return &s
|
|
37 |
}
|
|
38 |
|
|
39 |
// point implements encoding.TextMarshaler and can be used as a map key.
|
|
40 |
type point struct{ x, y int }
|
|
41 |
|
|
42 |
func (p point) MarshalText() ([]byte, error) {
|
|
43 |
return []byte(fmt.Sprintf("(%d, %d)", p.x, p.y)), nil
|
|
44 |
}
|
|
45 |
|
|
46 |
// pointErr implements encoding.TextMarshaler but returns an error.
|
|
47 |
type pointErr struct{ x, y int }
|
|
48 |
|
|
49 |
func (p pointErr) MarshalText() ([]byte, error) {
|
|
50 |
return nil, fmt.Errorf("uh oh: %d, %d", p.x, p.y)
|
37 | 51 |
}
|
38 | 52 |
|
39 | 53 |
// Logging this should result in the MarshalLog() value.
|
|
288 | 302 |
exp: `{"9.5":3}`,
|
289 | 303 |
},
|
290 | 304 |
{
|
|
305 |
val: map[point]int{
|
|
306 |
{x: 1, y: 2}: 3,
|
|
307 |
},
|
|
308 |
},
|
|
309 |
{
|
|
310 |
val: map[pointErr]int{
|
|
311 |
{x: 1, y: 2}: 3,
|
|
312 |
},
|
|
313 |
exp: `{"<error-MarshalText: uh oh: 1, 2>":3}`,
|
|
314 |
},
|
|
315 |
{
|
291 | 316 |
val: struct {
|
292 | 317 |
X int `json:"x"`
|
293 | 318 |
Y int `json:"y"`
|
|
495 | 520 |
} else {
|
496 | 521 |
jb, err := json.Marshal(tc.val)
|
497 | 522 |
if err != nil {
|
498 | |
t.Fatalf("[%d]: unexpected error: %v", i, err)
|
|
523 |
t.Fatalf("[%d]: unexpected error: %v\ngot: %q", i, err, ours)
|
499 | 524 |
}
|
500 | 525 |
want = string(jb)
|
501 | 526 |
}
|