tlog.app/go/tlog@v0.23.1/tlwire/encoder_value.go (about)

     1  package tlwire
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"reflect"
     7  	"time"
     8  	"unsafe"
     9  
    10  	"tlog.app/go/loc"
    11  
    12  	"tlog.app/go/tlog/low"
    13  )
    14  
    15  type (
    16  	TlogAppender interface {
    17  		TlogAppend(b []byte) []byte
    18  	}
    19  
    20  	ptrSet map[unsafe.Pointer]struct{}
    21  
    22  	ValueEncoder func(e *Encoder, b []byte, val interface{}) []byte
    23  
    24  	//nolint:structcheck
    25  	eface struct {
    26  		typ unsafe.Pointer
    27  		ptr unsafe.Pointer
    28  	}
    29  
    30  	//nolint:structcheck
    31  	reflectValue struct {
    32  		typ  unsafe.Pointer
    33  		ptr  unsafe.Pointer
    34  		flag uintptr
    35  	}
    36  
    37  	encoders map[unsafe.Pointer]ValueEncoder
    38  )
    39  
    40  var defaultEncoders = encoders{}
    41  
    42  func SetEncoder(tp interface{}, encoder ValueEncoder) {
    43  	defaultEncoders.Set(tp, encoder)
    44  }
    45  
    46  func (e *Encoder) SetEncoder(tp interface{}, encoder ValueEncoder) {
    47  	if e.custom == nil {
    48  		e.custom = encoders{}
    49  	}
    50  
    51  	e.custom.Set(tp, encoder)
    52  }
    53  
    54  func (e encoders) Set(tp interface{}, encoder ValueEncoder) {
    55  	if tp == nil {
    56  		panic("nil type")
    57  	}
    58  
    59  	ef := *(*eface)(unsafe.Pointer(&tp))
    60  
    61  	e[ef.typ] = encoder
    62  
    63  	if encoder == nil {
    64  		delete(e, ef.typ)
    65  	}
    66  }
    67  
    68  func init() {
    69  	SetEncoder(loc.PC(0), func(e *Encoder, b []byte, x interface{}) []byte {
    70  		return Encoder{}.AppendCaller(b, x.(loc.PC))
    71  	})
    72  	SetEncoder(loc.PCs(nil), func(e *Encoder, b []byte, x interface{}) []byte {
    73  		return Encoder{}.AppendCallers(b, x.(loc.PCs))
    74  	})
    75  
    76  	SetEncoder(time.Time{}, func(e *Encoder, b []byte, x interface{}) []byte {
    77  		return Encoder{}.AppendTimeTZ(b, x.(time.Time))
    78  	})
    79  	SetEncoder((*time.Time)(nil), func(e *Encoder, b []byte, x interface{}) []byte {
    80  		return Encoder{}.AppendTimeTZ(b, *x.(*time.Time))
    81  	})
    82  
    83  	SetEncoder(time.Duration(0), func(e *Encoder, b []byte, x interface{}) []byte {
    84  		return Encoder{}.AppendDuration(b, x.(time.Duration))
    85  	})
    86  	SetEncoder((*time.Duration)(nil), func(e *Encoder, b []byte, x interface{}) []byte {
    87  		return Encoder{}.AppendDuration(b, *x.(*time.Duration))
    88  	})
    89  
    90  	SetEncoder((*url.URL)(nil), func(e *Encoder, b []byte, x interface{}) []byte {
    91  		u := x.(*url.URL)
    92  		if u == nil {
    93  			return Encoder{}.AppendNil(b)
    94  		}
    95  
    96  		return Encoder{}.AppendString(b, u.String())
    97  	})
    98  }
    99  
   100  func (e *Encoder) AppendKeyValue(b []byte, key string, v interface{}) []byte {
   101  	b = e.AppendKey(b, key)
   102  	b = e.AppendValue(b, v)
   103  	return b
   104  }
   105  
   106  //go:linkname appendValue tlog.app/go/tlog/tlwire.(*Encoder).appendValue
   107  //go:noescape
   108  func appendValue(e *Encoder, b []byte, v interface{}) []byte
   109  
   110  func (e *Encoder) AppendValue(b []byte, v interface{}) []byte {
   111  	return appendValue(e, b, v)
   112  }
   113  
   114  func (e *Encoder) AppendValueSafe(b []byte, v interface{}) []byte {
   115  	return e.appendValue(b, v)
   116  }
   117  
   118  // Called through linkname hack as appendValue from (Encoder).AppendValue.
   119  func (e *Encoder) appendValue(b []byte, v interface{}) []byte {
   120  	if v == nil {
   121  		return append(b, Special|Nil)
   122  	}
   123  
   124  	r := reflect.ValueOf(v)
   125  
   126  	return e.appendRaw(b, r, ptrSet{})
   127  }
   128  
   129  func (e *Encoder) appendRaw(b []byte, r reflect.Value, visited ptrSet) []byte { //nolint:gocognit,cyclop
   130  	if r.CanInterface() {
   131  		//	v := r.Interface()
   132  		v := valueInterface(r)
   133  
   134  		//	if r.Type().Comparable() && v != r.Interface() {
   135  		//		panic(fmt.Sprintf("not equal interface %v: %x %v %v", r, value(r), raweface(v), raweface(r.Interface())))
   136  		//	}
   137  
   138  		ef := raweface(v)
   139  
   140  		if e != nil {
   141  			if enc, ok := e.custom[ef.typ]; ok {
   142  				return enc(e, b, v)
   143  			}
   144  		}
   145  
   146  		if enc, ok := defaultEncoders[ef.typ]; ok {
   147  			return enc(e, b, v)
   148  		}
   149  
   150  		switch v := v.(type) {
   151  		case TlogAppender:
   152  			return v.TlogAppend(b)
   153  		case interface {
   154  			ProtoMessage()
   155  		}:
   156  		case error:
   157  			return e.AppendError(b, v)
   158  		case fmt.Stringer:
   159  			return e.AppendString(b, v.String())
   160  		}
   161  	}
   162  
   163  	switch r.Kind() {
   164  	case reflect.String:
   165  		return e.AppendString(b, r.String())
   166  	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
   167  		return e.AppendInt64(b, r.Int())
   168  	case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
   169  		return e.AppendUint64(b, r.Uint())
   170  	case reflect.Float64, reflect.Float32:
   171  		return e.AppendFloat(b, r.Float())
   172  	case reflect.Ptr, reflect.Interface:
   173  		if r.IsNil() {
   174  			return append(b, Special|Nil)
   175  		}
   176  
   177  		if r.Kind() == reflect.Ptr {
   178  			ptr := unsafe.Pointer(r.Pointer())
   179  
   180  			if visited == nil {
   181  				visited = make(map[unsafe.Pointer]struct{})
   182  			}
   183  
   184  			if _, ok := visited[ptr]; ok {
   185  				return append(b, Special|SelfRef)
   186  			}
   187  
   188  			visited[ptr] = struct{}{}
   189  
   190  			defer delete(visited, ptr)
   191  		}
   192  
   193  		r = r.Elem()
   194  
   195  		return e.appendRaw(b, r, visited)
   196  	case reflect.Slice, reflect.Array:
   197  		if r.Type().Elem().Kind() == reflect.Uint8 {
   198  			if r.Kind() == reflect.Array {
   199  				if r.CanAddr() {
   200  					r = r.Slice(0, r.Len())
   201  				} else {
   202  					return e.AppendTagString(b, Bytes, low.UnsafeString(low.InterfaceData(r.Interface()), r.Len()))
   203  				}
   204  			}
   205  
   206  			return e.AppendBytes(b, r.Bytes())
   207  		}
   208  
   209  		l := r.Len()
   210  
   211  		b = e.AppendTag(b, Array, l)
   212  
   213  		for i := 0; i < l; i++ {
   214  			b = e.appendRaw(b, r.Index(i), visited)
   215  		}
   216  
   217  		return b
   218  	case reflect.Map:
   219  		l := r.Len()
   220  
   221  		b = e.AppendTag(b, Map, l)
   222  
   223  		it := r.MapRange()
   224  
   225  		for it.Next() {
   226  			b = e.appendRaw(b, it.Key(), visited)
   227  			b = e.appendRaw(b, it.Value(), visited)
   228  		}
   229  
   230  		return b
   231  	case reflect.Struct:
   232  		return e.appendStruct(b, r, visited)
   233  	case reflect.Bool:
   234  		if r.Bool() {
   235  			return append(b, Special|True)
   236  		} else { //nolint:golint
   237  			return append(b, Special|False)
   238  		}
   239  	case reflect.Func:
   240  		return append(b, Special|Undefined)
   241  	case reflect.Uintptr:
   242  		b = append(b, Semantic|Hex)
   243  		return e.AppendTag64(b, Int, r.Uint())
   244  	case reflect.UnsafePointer:
   245  		b = append(b, Semantic|Hex)
   246  		return e.AppendTag64(b, Int, uint64(r.Pointer()))
   247  	default:
   248  		panic(r)
   249  	}
   250  }
   251  
   252  func (e *Encoder) appendStruct(b []byte, r reflect.Value, visited ptrSet) []byte {
   253  	t := r.Type()
   254  
   255  	b = append(b, Map|LenBreak)
   256  
   257  	b = e.appendStructFields(b, t, r, visited)
   258  
   259  	b = append(b, Special|Break)
   260  
   261  	return b
   262  }
   263  
   264  func (e *Encoder) appendStructFields(b []byte, t reflect.Type, r reflect.Value, visited ptrSet) []byte {
   265  	//	fmt.Fprintf(os.Stderr, "appendStructFields: %v  ctx %p %d\n", t, visited, len(visited))
   266  
   267  	s := parseStruct(t)
   268  
   269  	for _, fc := range s.fs {
   270  		fv := r.Field(fc.Idx)
   271  
   272  		if fc.OmitEmpty && fv.IsZero() {
   273  			continue
   274  		}
   275  
   276  		ft := fv.Type()
   277  
   278  		if fc.Embed && ft.Kind() == reflect.Struct {
   279  			b = e.appendStructFields(b, ft, fv, visited)
   280  
   281  			continue
   282  		}
   283  
   284  		b = e.AppendString(b, fc.Name)
   285  
   286  		if fc.Hex {
   287  			b = append(b, Semantic|Hex)
   288  		}
   289  
   290  		b = e.appendRaw(b, fv, visited)
   291  	}
   292  
   293  	return b
   294  }
   295  
   296  func value(v reflect.Value) reflectValue {
   297  	return *(*reflectValue)(unsafe.Pointer(&v))
   298  }
   299  
   300  func valueInterface(r reflect.Value) interface{} {
   301  	v := value(r)
   302  
   303  	if r.Kind() == reflect.Interface {
   304  		// Special case: return the element inside the interface.
   305  		// Empty interface has one layout, all interfaces with
   306  		// methods have a second layout.
   307  		if r.NumMethod() == 0 {
   308  			return *(*interface{})(v.ptr)
   309  		}
   310  		return *(*interface {
   311  			M()
   312  		})(v.ptr)
   313  	}
   314  
   315  	const flagAddr = 1 << 8
   316  
   317  	v.flag &^= flagAddr
   318  
   319  	return reflect_packEface(v)
   320  }
   321  
   322  //go:linkname reflect_packEface reflect.packEface
   323  func reflect_packEface(reflectValue) interface{}
   324  
   325  func raweface(x interface{}) eface {
   326  	return *(*eface)(unsafe.Pointer(&x))
   327  }