mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 21:32:24 -06:00 
			
		
		
		
	
		
			
	
	
		
			457 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			457 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2022 The Go Authors. All rights reserved.
							 | 
						||
| 
								 | 
							
								// Use of this source code is governed by a BSD-style
							 | 
						||
| 
								 | 
							
								// license that can be found in the LICENSE file.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package slog
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"math"
							 | 
						||
| 
								 | 
							
									"runtime"
							 | 
						||
| 
								 | 
							
									"strconv"
							 | 
						||
| 
								 | 
							
									"strings"
							 | 
						||
| 
								 | 
							
									"time"
							 | 
						||
| 
								 | 
							
									"unsafe"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									"golang.org/x/exp/slices"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// A Value can represent any Go value, but unlike type any,
							 | 
						||
| 
								 | 
							
								// it can represent most small values without an allocation.
							 | 
						||
| 
								 | 
							
								// The zero Value corresponds to nil.
							 | 
						||
| 
								 | 
							
								type Value struct {
							 | 
						||
| 
								 | 
							
									_ [0]func() // disallow ==
							 | 
						||
| 
								 | 
							
									// num holds the value for Kinds Int64, Uint64, Float64, Bool and Duration,
							 | 
						||
| 
								 | 
							
									// the string length for KindString, and nanoseconds since the epoch for KindTime.
							 | 
						||
| 
								 | 
							
									num uint64
							 | 
						||
| 
								 | 
							
									// If any is of type Kind, then the value is in num as described above.
							 | 
						||
| 
								 | 
							
									// If any is of type *time.Location, then the Kind is Time and time.Time value
							 | 
						||
| 
								 | 
							
									// can be constructed from the Unix nanos in num and the location (monotonic time
							 | 
						||
| 
								 | 
							
									// is not preserved).
							 | 
						||
| 
								 | 
							
									// If any is of type stringptr, then the Kind is String and the string value
							 | 
						||
| 
								 | 
							
									// consists of the length in num and the pointer in any.
							 | 
						||
| 
								 | 
							
									// Otherwise, the Kind is Any and any is the value.
							 | 
						||
| 
								 | 
							
									// (This implies that Attrs cannot store values of type Kind, *time.Location
							 | 
						||
| 
								 | 
							
									// or stringptr.)
							 | 
						||
| 
								 | 
							
									any any
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Kind is the kind of a Value.
							 | 
						||
| 
								 | 
							
								type Kind int
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// The following list is sorted alphabetically, but it's also important that
							 | 
						||
| 
								 | 
							
								// KindAny is 0 so that a zero Value represents nil.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									KindAny Kind = iota
							 | 
						||
| 
								 | 
							
									KindBool
							 | 
						||
| 
								 | 
							
									KindDuration
							 | 
						||
| 
								 | 
							
									KindFloat64
							 | 
						||
| 
								 | 
							
									KindInt64
							 | 
						||
| 
								 | 
							
									KindString
							 | 
						||
| 
								 | 
							
									KindTime
							 | 
						||
| 
								 | 
							
									KindUint64
							 | 
						||
| 
								 | 
							
									KindGroup
							 | 
						||
| 
								 | 
							
									KindLogValuer
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var kindStrings = []string{
							 | 
						||
| 
								 | 
							
									"Any",
							 | 
						||
| 
								 | 
							
									"Bool",
							 | 
						||
| 
								 | 
							
									"Duration",
							 | 
						||
| 
								 | 
							
									"Float64",
							 | 
						||
| 
								 | 
							
									"Int64",
							 | 
						||
| 
								 | 
							
									"String",
							 | 
						||
| 
								 | 
							
									"Time",
							 | 
						||
| 
								 | 
							
									"Uint64",
							 | 
						||
| 
								 | 
							
									"Group",
							 | 
						||
| 
								 | 
							
									"LogValuer",
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (k Kind) String() string {
							 | 
						||
| 
								 | 
							
									if k >= 0 && int(k) < len(kindStrings) {
							 | 
						||
| 
								 | 
							
										return kindStrings[k]
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return "<unknown slog.Kind>"
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Unexported version of Kind, just so we can store Kinds in Values.
							 | 
						||
| 
								 | 
							
								// (No user-provided value has this type.)
							 | 
						||
| 
								 | 
							
								type kind Kind
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Kind returns v's Kind.
							 | 
						||
| 
								 | 
							
								func (v Value) Kind() Kind {
							 | 
						||
| 
								 | 
							
									switch x := v.any.(type) {
							 | 
						||
| 
								 | 
							
									case Kind:
							 | 
						||
| 
								 | 
							
										return x
							 | 
						||
| 
								 | 
							
									case stringptr:
							 | 
						||
| 
								 | 
							
										return KindString
							 | 
						||
| 
								 | 
							
									case timeLocation:
							 | 
						||
| 
								 | 
							
										return KindTime
							 | 
						||
| 
								 | 
							
									case groupptr:
							 | 
						||
| 
								 | 
							
										return KindGroup
							 | 
						||
| 
								 | 
							
									case LogValuer:
							 | 
						||
| 
								 | 
							
										return KindLogValuer
							 | 
						||
| 
								 | 
							
									case kind: // a kind is just a wrapper for a Kind
							 | 
						||
| 
								 | 
							
										return KindAny
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return KindAny
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////// Constructors
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// IntValue returns a Value for an int.
							 | 
						||
| 
								 | 
							
								func IntValue(v int) Value {
							 | 
						||
| 
								 | 
							
									return Int64Value(int64(v))
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Int64Value returns a Value for an int64.
							 | 
						||
| 
								 | 
							
								func Int64Value(v int64) Value {
							 | 
						||
| 
								 | 
							
									return Value{num: uint64(v), any: KindInt64}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Uint64Value returns a Value for a uint64.
							 | 
						||
| 
								 | 
							
								func Uint64Value(v uint64) Value {
							 | 
						||
| 
								 | 
							
									return Value{num: v, any: KindUint64}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Float64Value returns a Value for a floating-point number.
							 | 
						||
| 
								 | 
							
								func Float64Value(v float64) Value {
							 | 
						||
| 
								 | 
							
									return Value{num: math.Float64bits(v), any: KindFloat64}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// BoolValue returns a Value for a bool.
							 | 
						||
| 
								 | 
							
								func BoolValue(v bool) Value {
							 | 
						||
| 
								 | 
							
									u := uint64(0)
							 | 
						||
| 
								 | 
							
									if v {
							 | 
						||
| 
								 | 
							
										u = 1
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return Value{num: u, any: KindBool}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Unexported version of *time.Location, just so we can store *time.Locations in
							 | 
						||
| 
								 | 
							
								// Values. (No user-provided value has this type.)
							 | 
						||
| 
								 | 
							
								type timeLocation *time.Location
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// TimeValue returns a Value for a time.Time.
							 | 
						||
| 
								 | 
							
								// It discards the monotonic portion.
							 | 
						||
| 
								 | 
							
								func TimeValue(v time.Time) Value {
							 | 
						||
| 
								 | 
							
									if v.IsZero() {
							 | 
						||
| 
								 | 
							
										// UnixNano on the zero time is undefined, so represent the zero time
							 | 
						||
| 
								 | 
							
										// with a nil *time.Location instead. time.Time.Location method never
							 | 
						||
| 
								 | 
							
										// returns nil, so a Value with any == timeLocation(nil) cannot be
							 | 
						||
| 
								 | 
							
										// mistaken for any other Value, time.Time or otherwise.
							 | 
						||
| 
								 | 
							
										return Value{any: timeLocation(nil)}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return Value{num: uint64(v.UnixNano()), any: timeLocation(v.Location())}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// DurationValue returns a Value for a time.Duration.
							 | 
						||
| 
								 | 
							
								func DurationValue(v time.Duration) Value {
							 | 
						||
| 
								 | 
							
									return Value{num: uint64(v.Nanoseconds()), any: KindDuration}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AnyValue returns a Value for the supplied value.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// If the supplied value is of type Value, it is returned
							 | 
						||
| 
								 | 
							
								// unmodified.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Given a value of one of Go's predeclared string, bool, or
							 | 
						||
| 
								 | 
							
								// (non-complex) numeric types, AnyValue returns a Value of kind
							 | 
						||
| 
								 | 
							
								// String, Bool, Uint64, Int64, or Float64. The width of the
							 | 
						||
| 
								 | 
							
								// original numeric type is not preserved.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Given a time.Time or time.Duration value, AnyValue returns a Value of kind
							 | 
						||
| 
								 | 
							
								// KindTime or KindDuration. The monotonic time is not preserved.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// For nil, or values of all other types, including named types whose
							 | 
						||
| 
								 | 
							
								// underlying type is numeric, AnyValue returns a value of kind KindAny.
							 | 
						||
| 
								 | 
							
								func AnyValue(v any) Value {
							 | 
						||
| 
								 | 
							
									switch v := v.(type) {
							 | 
						||
| 
								 | 
							
									case string:
							 | 
						||
| 
								 | 
							
										return StringValue(v)
							 | 
						||
| 
								 | 
							
									case int:
							 | 
						||
| 
								 | 
							
										return Int64Value(int64(v))
							 | 
						||
| 
								 | 
							
									case uint:
							 | 
						||
| 
								 | 
							
										return Uint64Value(uint64(v))
							 | 
						||
| 
								 | 
							
									case int64:
							 | 
						||
| 
								 | 
							
										return Int64Value(v)
							 | 
						||
| 
								 | 
							
									case uint64:
							 | 
						||
| 
								 | 
							
										return Uint64Value(v)
							 | 
						||
| 
								 | 
							
									case bool:
							 | 
						||
| 
								 | 
							
										return BoolValue(v)
							 | 
						||
| 
								 | 
							
									case time.Duration:
							 | 
						||
| 
								 | 
							
										return DurationValue(v)
							 | 
						||
| 
								 | 
							
									case time.Time:
							 | 
						||
| 
								 | 
							
										return TimeValue(v)
							 | 
						||
| 
								 | 
							
									case uint8:
							 | 
						||
| 
								 | 
							
										return Uint64Value(uint64(v))
							 | 
						||
| 
								 | 
							
									case uint16:
							 | 
						||
| 
								 | 
							
										return Uint64Value(uint64(v))
							 | 
						||
| 
								 | 
							
									case uint32:
							 | 
						||
| 
								 | 
							
										return Uint64Value(uint64(v))
							 | 
						||
| 
								 | 
							
									case uintptr:
							 | 
						||
| 
								 | 
							
										return Uint64Value(uint64(v))
							 | 
						||
| 
								 | 
							
									case int8:
							 | 
						||
| 
								 | 
							
										return Int64Value(int64(v))
							 | 
						||
| 
								 | 
							
									case int16:
							 | 
						||
| 
								 | 
							
										return Int64Value(int64(v))
							 | 
						||
| 
								 | 
							
									case int32:
							 | 
						||
| 
								 | 
							
										return Int64Value(int64(v))
							 | 
						||
| 
								 | 
							
									case float64:
							 | 
						||
| 
								 | 
							
										return Float64Value(v)
							 | 
						||
| 
								 | 
							
									case float32:
							 | 
						||
| 
								 | 
							
										return Float64Value(float64(v))
							 | 
						||
| 
								 | 
							
									case []Attr:
							 | 
						||
| 
								 | 
							
										return GroupValue(v...)
							 | 
						||
| 
								 | 
							
									case Kind:
							 | 
						||
| 
								 | 
							
										return Value{any: kind(v)}
							 | 
						||
| 
								 | 
							
									case Value:
							 | 
						||
| 
								 | 
							
										return v
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return Value{any: v}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////// Accessors
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Any returns v's value as an any.
							 | 
						||
| 
								 | 
							
								func (v Value) Any() any {
							 | 
						||
| 
								 | 
							
									switch v.Kind() {
							 | 
						||
| 
								 | 
							
									case KindAny:
							 | 
						||
| 
								 | 
							
										if k, ok := v.any.(kind); ok {
							 | 
						||
| 
								 | 
							
											return Kind(k)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return v.any
							 | 
						||
| 
								 | 
							
									case KindLogValuer:
							 | 
						||
| 
								 | 
							
										return v.any
							 | 
						||
| 
								 | 
							
									case KindGroup:
							 | 
						||
| 
								 | 
							
										return v.group()
							 | 
						||
| 
								 | 
							
									case KindInt64:
							 | 
						||
| 
								 | 
							
										return int64(v.num)
							 | 
						||
| 
								 | 
							
									case KindUint64:
							 | 
						||
| 
								 | 
							
										return v.num
							 | 
						||
| 
								 | 
							
									case KindFloat64:
							 | 
						||
| 
								 | 
							
										return v.float()
							 | 
						||
| 
								 | 
							
									case KindString:
							 | 
						||
| 
								 | 
							
										return v.str()
							 | 
						||
| 
								 | 
							
									case KindBool:
							 | 
						||
| 
								 | 
							
										return v.bool()
							 | 
						||
| 
								 | 
							
									case KindDuration:
							 | 
						||
| 
								 | 
							
										return v.duration()
							 | 
						||
| 
								 | 
							
									case KindTime:
							 | 
						||
| 
								 | 
							
										return v.time()
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("bad kind: %s", v.Kind()))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Int64 returns v's value as an int64. It panics
							 | 
						||
| 
								 | 
							
								// if v is not a signed integer.
							 | 
						||
| 
								 | 
							
								func (v Value) Int64() int64 {
							 | 
						||
| 
								 | 
							
									if g, w := v.Kind(), KindInt64; g != w {
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return int64(v.num)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Uint64 returns v's value as a uint64. It panics
							 | 
						||
| 
								 | 
							
								// if v is not an unsigned integer.
							 | 
						||
| 
								 | 
							
								func (v Value) Uint64() uint64 {
							 | 
						||
| 
								 | 
							
									if g, w := v.Kind(), KindUint64; g != w {
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return v.num
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Bool returns v's value as a bool. It panics
							 | 
						||
| 
								 | 
							
								// if v is not a bool.
							 | 
						||
| 
								 | 
							
								func (v Value) Bool() bool {
							 | 
						||
| 
								 | 
							
									if g, w := v.Kind(), KindBool; g != w {
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return v.bool()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (v Value) bool() bool {
							 | 
						||
| 
								 | 
							
									return v.num == 1
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Duration returns v's value as a time.Duration. It panics
							 | 
						||
| 
								 | 
							
								// if v is not a time.Duration.
							 | 
						||
| 
								 | 
							
								func (v Value) Duration() time.Duration {
							 | 
						||
| 
								 | 
							
									if g, w := v.Kind(), KindDuration; g != w {
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return v.duration()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (v Value) duration() time.Duration {
							 | 
						||
| 
								 | 
							
									return time.Duration(int64(v.num))
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Float64 returns v's value as a float64. It panics
							 | 
						||
| 
								 | 
							
								// if v is not a float64.
							 | 
						||
| 
								 | 
							
								func (v Value) Float64() float64 {
							 | 
						||
| 
								 | 
							
									if g, w := v.Kind(), KindFloat64; g != w {
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return v.float()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (v Value) float() float64 {
							 | 
						||
| 
								 | 
							
									return math.Float64frombits(v.num)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Time returns v's value as a time.Time. It panics
							 | 
						||
| 
								 | 
							
								// if v is not a time.Time.
							 | 
						||
| 
								 | 
							
								func (v Value) Time() time.Time {
							 | 
						||
| 
								 | 
							
									if g, w := v.Kind(), KindTime; g != w {
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return v.time()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (v Value) time() time.Time {
							 | 
						||
| 
								 | 
							
									loc := v.any.(timeLocation)
							 | 
						||
| 
								 | 
							
									if loc == nil {
							 | 
						||
| 
								 | 
							
										return time.Time{}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return time.Unix(0, int64(v.num)).In(loc)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// LogValuer returns v's value as a LogValuer. It panics
							 | 
						||
| 
								 | 
							
								// if v is not a LogValuer.
							 | 
						||
| 
								 | 
							
								func (v Value) LogValuer() LogValuer {
							 | 
						||
| 
								 | 
							
									return v.any.(LogValuer)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Group returns v's value as a []Attr.
							 | 
						||
| 
								 | 
							
								// It panics if v's Kind is not KindGroup.
							 | 
						||
| 
								 | 
							
								func (v Value) Group() []Attr {
							 | 
						||
| 
								 | 
							
									if sp, ok := v.any.(groupptr); ok {
							 | 
						||
| 
								 | 
							
										return unsafe.Slice((*Attr)(sp), v.num)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									panic("Group: bad kind")
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (v Value) group() []Attr {
							 | 
						||
| 
								 | 
							
									return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////// Other
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Equal reports whether v and w represent the same Go value.
							 | 
						||
| 
								 | 
							
								func (v Value) Equal(w Value) bool {
							 | 
						||
| 
								 | 
							
									k1 := v.Kind()
							 | 
						||
| 
								 | 
							
									k2 := w.Kind()
							 | 
						||
| 
								 | 
							
									if k1 != k2 {
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									switch k1 {
							 | 
						||
| 
								 | 
							
									case KindInt64, KindUint64, KindBool, KindDuration:
							 | 
						||
| 
								 | 
							
										return v.num == w.num
							 | 
						||
| 
								 | 
							
									case KindString:
							 | 
						||
| 
								 | 
							
										return v.str() == w.str()
							 | 
						||
| 
								 | 
							
									case KindFloat64:
							 | 
						||
| 
								 | 
							
										return v.float() == w.float()
							 | 
						||
| 
								 | 
							
									case KindTime:
							 | 
						||
| 
								 | 
							
										return v.time().Equal(w.time())
							 | 
						||
| 
								 | 
							
									case KindAny, KindLogValuer:
							 | 
						||
| 
								 | 
							
										return v.any == w.any // may panic if non-comparable
							 | 
						||
| 
								 | 
							
									case KindGroup:
							 | 
						||
| 
								 | 
							
										return slices.EqualFunc(v.group(), w.group(), Attr.Equal)
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("bad kind: %s", k1))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// append appends a text representation of v to dst.
							 | 
						||
| 
								 | 
							
								// v is formatted as with fmt.Sprint.
							 | 
						||
| 
								 | 
							
								func (v Value) append(dst []byte) []byte {
							 | 
						||
| 
								 | 
							
									switch v.Kind() {
							 | 
						||
| 
								 | 
							
									case KindString:
							 | 
						||
| 
								 | 
							
										return append(dst, v.str()...)
							 | 
						||
| 
								 | 
							
									case KindInt64:
							 | 
						||
| 
								 | 
							
										return strconv.AppendInt(dst, int64(v.num), 10)
							 | 
						||
| 
								 | 
							
									case KindUint64:
							 | 
						||
| 
								 | 
							
										return strconv.AppendUint(dst, v.num, 10)
							 | 
						||
| 
								 | 
							
									case KindFloat64:
							 | 
						||
| 
								 | 
							
										return strconv.AppendFloat(dst, v.float(), 'g', -1, 64)
							 | 
						||
| 
								 | 
							
									case KindBool:
							 | 
						||
| 
								 | 
							
										return strconv.AppendBool(dst, v.bool())
							 | 
						||
| 
								 | 
							
									case KindDuration:
							 | 
						||
| 
								 | 
							
										return append(dst, v.duration().String()...)
							 | 
						||
| 
								 | 
							
									case KindTime:
							 | 
						||
| 
								 | 
							
										return append(dst, v.time().String()...)
							 | 
						||
| 
								 | 
							
									case KindGroup:
							 | 
						||
| 
								 | 
							
										return fmt.Append(dst, v.group())
							 | 
						||
| 
								 | 
							
									case KindAny, KindLogValuer:
							 | 
						||
| 
								 | 
							
										return fmt.Append(dst, v.any)
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("bad kind: %s", v.Kind()))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// A LogValuer is any Go value that can convert itself into a Value for logging.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This mechanism may be used to defer expensive operations until they are
							 | 
						||
| 
								 | 
							
								// needed, or to expand a single value into a sequence of components.
							 | 
						||
| 
								 | 
							
								type LogValuer interface {
							 | 
						||
| 
								 | 
							
									LogValue() Value
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const maxLogValues = 100
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Resolve repeatedly calls LogValue on v while it implements LogValuer,
							 | 
						||
| 
								 | 
							
								// and returns the result.
							 | 
						||
| 
								 | 
							
								// If v resolves to a group, the group's attributes' values are not recursively
							 | 
						||
| 
								 | 
							
								// resolved.
							 | 
						||
| 
								 | 
							
								// If the number of LogValue calls exceeds a threshold, a Value containing an
							 | 
						||
| 
								 | 
							
								// error is returned.
							 | 
						||
| 
								 | 
							
								// Resolve's return value is guaranteed not to be of Kind KindLogValuer.
							 | 
						||
| 
								 | 
							
								func (v Value) Resolve() (rv Value) {
							 | 
						||
| 
								 | 
							
									orig := v
							 | 
						||
| 
								 | 
							
									defer func() {
							 | 
						||
| 
								 | 
							
										if r := recover(); r != nil {
							 | 
						||
| 
								 | 
							
											rv = AnyValue(fmt.Errorf("LogValue panicked\n%s", stack(3, 5)))
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for i := 0; i < maxLogValues; i++ {
							 | 
						||
| 
								 | 
							
										if v.Kind() != KindLogValuer {
							 | 
						||
| 
								 | 
							
											return v
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										v = v.LogValuer().LogValue()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									err := fmt.Errorf("LogValue called too many times on Value of type %T", orig.Any())
							 | 
						||
| 
								 | 
							
									return AnyValue(err)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func stack(skip, nFrames int) string {
							 | 
						||
| 
								 | 
							
									pcs := make([]uintptr, nFrames+1)
							 | 
						||
| 
								 | 
							
									n := runtime.Callers(skip+1, pcs)
							 | 
						||
| 
								 | 
							
									if n == 0 {
							 | 
						||
| 
								 | 
							
										return "(no stack)"
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									frames := runtime.CallersFrames(pcs[:n])
							 | 
						||
| 
								 | 
							
									var b strings.Builder
							 | 
						||
| 
								 | 
							
									i := 0
							 | 
						||
| 
								 | 
							
									for {
							 | 
						||
| 
								 | 
							
										frame, more := frames.Next()
							 | 
						||
| 
								 | 
							
										fmt.Fprintf(&b, "called from %s (%s:%d)\n", frame.Function, frame.File, frame.Line)
							 | 
						||
| 
								 | 
							
										if !more {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										i++
							 | 
						||
| 
								 | 
							
										if i >= nFrames {
							 | 
						||
| 
								 | 
							
											fmt.Fprintf(&b, "(rest of stack elided)\n")
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return b.String()
							 | 
						||
| 
								 | 
							
								}
							 |