// 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. //go:build !safe_values package slog // This file defines the most compact representation of Value. import ( "reflect" "unsafe" ) // 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 { // 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 } type ( stringptr unsafe.Pointer // used in Value.any when the Value is a string groupptr unsafe.Pointer // used in Value.any when the Value is a []Attr ) // 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 } } // StringValue returns a new Value for a string. func StringValue(value string) Value { hdr := (*reflect.StringHeader)(unsafe.Pointer(&value)) return Value{num: uint64(hdr.Len), any: stringptr(hdr.Data)} } func (v Value) str() string { var s string hdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) hdr.Data = uintptr(v.any.(stringptr)) hdr.Len = int(v.num) return s } // String returns Value's value as a string, formatted like fmt.Sprint. Unlike // the methods Int64, Float64, and so on, which panic if v is of the // wrong kind, String never panics. func (v Value) String() string { if sp, ok := v.any.(stringptr); ok { // Inlining this code makes a huge difference. var s string hdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) hdr.Data = uintptr(sp) hdr.Len = int(v.num) return s } var buf []byte return string(v.append(buf)) } func groupValue(as []Attr) Value { hdr := (*reflect.SliceHeader)(unsafe.Pointer(&as)) return Value{num: uint64(hdr.Len), any: groupptr(hdr.Data)} } // group returns the Value's value as a []Attr. // It panics if the Value'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) uncheckedGroup() []Attr { return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num) }