github.com/nikandfor/tlog@v0.21.3/tlwire/dumper.go (about) 1 package tlwire 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "io" 7 8 "github.com/nikandfor/hacked/hfmt" 9 10 "github.com/nikandfor/tlog/low" 11 ) 12 13 type ( 14 Dumper struct { 15 LowDecoder 16 17 io.Writer 18 pos int64 19 20 NoGlobalOffset bool 21 22 b []byte 23 } 24 ) 25 26 func Dump(p []byte) (r string) { 27 if len(p) == 0 { 28 return "" 29 } 30 31 d := Dumper{ 32 NoGlobalOffset: true, 33 b: make([]byte, len(p)*3), 34 } 35 36 defer func() { 37 e := recover() 38 if e == nil { 39 return 40 } 41 42 r = fmt.Sprintf("%s\npanic: %v\nhex.Dump\n%s", d.b, e, hex.Dump(p)) 43 }() 44 45 _, _ = d.Write(p) 46 47 d.b = hfmt.Appendf(d.b, "%4x\n", len(p)) 48 49 return string(d.b) 50 } 51 52 func NewDumper(w io.Writer) *Dumper { 53 return &Dumper{Writer: w} 54 } 55 56 func (d *Dumper) Write(p []byte) (n int, err error) { 57 d.b = d.b[:0] 58 59 defer func() { 60 rp := recover() 61 if rp == nil { 62 return 63 } 64 65 hfmt.Appendf(d.b, "panic: %v\n%s", rp, hex.Dump(p)) 66 }() 67 68 var i int 69 70 for i < len(p) { 71 i = d.dump(p, i, 0) 72 } 73 74 d.pos += int64(i) 75 76 if d.Writer != nil { 77 _, err = d.Writer.Write(d.b) 78 } 79 80 return len(p), err 81 } 82 83 func (d *Dumper) dump(p []byte, st, depth int) (i int) { 84 tag, sub, i := d.Tag(p, st) 85 86 if !d.NoGlobalOffset { 87 d.b = hfmt.Appendf(d.b, "%8x ", d.pos+int64(st)) 88 } 89 90 d.b = hfmt.Appendf(d.b, "%4x %s% x - ", st, low.Spaces[:depth*2], p[st:i]) 91 92 switch tag { 93 case Int, Neg: 94 var v int64 95 v, i = d.Signed(p, st) 96 97 d.b = hfmt.Appendf(d.b, "int %10v\n", v) 98 case Bytes, String: 99 var s []byte 100 s, i = d.Bytes(p, st) 101 102 if tag == Bytes { 103 d.b = hfmt.Appendf(d.b, "% x\n", s) 104 } else { 105 d.b = hfmt.Appendf(d.b, "%q\n", s) 106 } 107 case Array, Map: 108 tg := "array" 109 if tag == Map { 110 tg = "map" 111 } 112 113 d.b = hfmt.Appendf(d.b, "%v: len %v\n", tg, sub) 114 115 for el := 0; sub == -1 || el < int(sub); el++ { 116 if sub == -1 && d.Break(p, &i) { 117 i = d.dump(p, i-1, depth+1) 118 break 119 } 120 121 i = d.dump(p, i, depth+1) 122 123 if tag == Map { 124 i = d.dump(p, i, depth+1) 125 } 126 } 127 case Semantic: 128 d.b = hfmt.Appendf(d.b, "semantic %2x\n", sub) 129 130 i = d.dump(p, i, depth+1) 131 case Special: 132 switch sub { 133 case False: 134 d.b = hfmt.Appendf(d.b, "false\n") 135 case True: 136 d.b = hfmt.Appendf(d.b, "true\n") 137 case Nil: 138 d.b = hfmt.Appendf(d.b, "null\n") 139 case Undefined: 140 d.b = hfmt.Appendf(d.b, "undefined\n") 141 case Float8, Float16, Float32, Float64: 142 var f float64 143 144 f, i = d.Float(p, st) 145 146 d.b = hfmt.Appendf(d.b, "%v\n", f) 147 case Break: 148 d.b = hfmt.Appendf(d.b, "break\n") 149 default: 150 d.b = hfmt.Appendf(d.b, "special: %x\n", sub) 151 152 panic("unsupported special") 153 } 154 } 155 156 return 157 }