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  }