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