Source file
src/log/slog/value.go
1
2
3
4
5 package slog
6
7 import (
8 "fmt"
9 "math"
10 "runtime"
11 "slices"
12 "strconv"
13 "strings"
14 "time"
15 "unsafe"
16 )
17
18
19
20
21 type Value struct {
22 _ [0]func()
23
24
25 num uint64
26
27
28
29
30
31
32
33
34
35 any any
36 }
37
38 type (
39 stringptr *byte
40 groupptr *Attr
41 )
42
43
44 type Kind int
45
46
47
48
49 const (
50 KindAny Kind = iota
51 KindBool
52 KindDuration
53 KindFloat64
54 KindInt64
55 KindString
56 KindTime
57 KindUint64
58 KindGroup
59 KindLogValuer
60 )
61
62 var kindStrings = []string{
63 "Any",
64 "Bool",
65 "Duration",
66 "Float64",
67 "Int64",
68 "String",
69 "Time",
70 "Uint64",
71 "Group",
72 "LogValuer",
73 }
74
75 func (k Kind) String() string {
76 if k >= 0 && int(k) < len(kindStrings) {
77 return kindStrings[k]
78 }
79 return "<unknown slog.Kind>"
80 }
81
82
83
84 type kind Kind
85
86
87 func (v Value) Kind() Kind {
88 switch x := v.any.(type) {
89 case Kind:
90 return x
91 case stringptr:
92 return KindString
93 case timeLocation:
94 return KindTime
95 case groupptr:
96 return KindGroup
97 case LogValuer:
98 return KindLogValuer
99 case kind:
100 return KindAny
101 default:
102 return KindAny
103 }
104 }
105
106
107
108
109 func StringValue(value string) Value {
110 return Value{num: uint64(len(value)), any: stringptr(unsafe.StringData(value))}
111 }
112
113
114 func IntValue(v int) Value {
115 return Int64Value(int64(v))
116 }
117
118
119 func Int64Value(v int64) Value {
120 return Value{num: uint64(v), any: KindInt64}
121 }
122
123
124 func Uint64Value(v uint64) Value {
125 return Value{num: v, any: KindUint64}
126 }
127
128
129 func Float64Value(v float64) Value {
130 return Value{num: math.Float64bits(v), any: KindFloat64}
131 }
132
133
134 func BoolValue(v bool) Value {
135 u := uint64(0)
136 if v {
137 u = 1
138 }
139 return Value{num: u, any: KindBool}
140 }
141
142
143
144 type timeLocation *time.Location
145
146
147
148 func TimeValue(v time.Time) Value {
149 if v.IsZero() {
150
151
152
153
154 return Value{any: timeLocation(nil)}
155 }
156 return Value{num: uint64(v.UnixNano()), any: timeLocation(v.Location())}
157 }
158
159
160 func DurationValue(v time.Duration) Value {
161 return Value{num: uint64(v.Nanoseconds()), any: KindDuration}
162 }
163
164
165
166 func GroupValue(as ...Attr) Value {
167
168
169
170 if n := countEmptyGroups(as); n > 0 {
171 as2 := make([]Attr, 0, len(as)-n)
172 for _, a := range as {
173 if !a.Value.isEmptyGroup() {
174 as2 = append(as2, a)
175 }
176 }
177 as = as2
178 }
179 return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))}
180 }
181
182
183 func countEmptyGroups(as []Attr) int {
184 n := 0
185 for _, a := range as {
186 if a.Value.isEmptyGroup() {
187 n++
188 }
189 }
190 return n
191 }
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208 func AnyValue(v any) Value {
209 switch v := v.(type) {
210 case string:
211 return StringValue(v)
212 case int:
213 return Int64Value(int64(v))
214 case uint:
215 return Uint64Value(uint64(v))
216 case int64:
217 return Int64Value(v)
218 case uint64:
219 return Uint64Value(v)
220 case bool:
221 return BoolValue(v)
222 case time.Duration:
223 return DurationValue(v)
224 case time.Time:
225 return TimeValue(v)
226 case uint8:
227 return Uint64Value(uint64(v))
228 case uint16:
229 return Uint64Value(uint64(v))
230 case uint32:
231 return Uint64Value(uint64(v))
232 case uintptr:
233 return Uint64Value(uint64(v))
234 case int8:
235 return Int64Value(int64(v))
236 case int16:
237 return Int64Value(int64(v))
238 case int32:
239 return Int64Value(int64(v))
240 case float64:
241 return Float64Value(v)
242 case float32:
243 return Float64Value(float64(v))
244 case []Attr:
245 return GroupValue(v...)
246 case Kind:
247 return Value{any: kind(v)}
248 case Value:
249 return v
250 default:
251 return Value{any: v}
252 }
253 }
254
255
256
257
258 func (v Value) Any() any {
259 switch v.Kind() {
260 case KindAny:
261 if k, ok := v.any.(kind); ok {
262 return Kind(k)
263 }
264 return v.any
265 case KindLogValuer:
266 return v.any
267 case KindGroup:
268 return v.group()
269 case KindInt64:
270 return int64(v.num)
271 case KindUint64:
272 return v.num
273 case KindFloat64:
274 return v.float()
275 case KindString:
276 return v.str()
277 case KindBool:
278 return v.bool()
279 case KindDuration:
280 return v.duration()
281 case KindTime:
282 return v.time()
283 default:
284 panic(fmt.Sprintf("bad kind: %s", v.Kind()))
285 }
286 }
287
288
289
290
291 func (v Value) String() string {
292 if sp, ok := v.any.(stringptr); ok {
293 return unsafe.String(sp, v.num)
294 }
295 var buf []byte
296 return string(v.append(buf))
297 }
298
299 func (v Value) str() string {
300 return unsafe.String(v.any.(stringptr), v.num)
301 }
302
303
304
305 func (v Value) Int64() int64 {
306 if g, w := v.Kind(), KindInt64; g != w {
307 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
308 }
309 return int64(v.num)
310 }
311
312
313
314 func (v Value) Uint64() uint64 {
315 if g, w := v.Kind(), KindUint64; g != w {
316 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
317 }
318 return v.num
319 }
320
321
322
323 func (v Value) Bool() bool {
324 if g, w := v.Kind(), KindBool; g != w {
325 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
326 }
327 return v.bool()
328 }
329
330 func (v Value) bool() bool {
331 return v.num == 1
332 }
333
334
335
336 func (v Value) Duration() time.Duration {
337 if g, w := v.Kind(), KindDuration; g != w {
338 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
339 }
340
341 return v.duration()
342 }
343
344 func (v Value) duration() time.Duration {
345 return time.Duration(int64(v.num))
346 }
347
348
349
350 func (v Value) Float64() float64 {
351 if g, w := v.Kind(), KindFloat64; g != w {
352 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
353 }
354
355 return v.float()
356 }
357
358 func (v Value) float() float64 {
359 return math.Float64frombits(v.num)
360 }
361
362
363
364 func (v Value) Time() time.Time {
365 if g, w := v.Kind(), KindTime; g != w {
366 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
367 }
368 return v.time()
369 }
370
371 func (v Value) time() time.Time {
372 loc := v.any.(timeLocation)
373 if loc == nil {
374 return time.Time{}
375 }
376 return time.Unix(0, int64(v.num)).In(loc)
377 }
378
379
380
381 func (v Value) LogValuer() LogValuer {
382 return v.any.(LogValuer)
383 }
384
385
386
387 func (v Value) Group() []Attr {
388 if sp, ok := v.any.(groupptr); ok {
389 return unsafe.Slice((*Attr)(sp), v.num)
390 }
391 panic("Group: bad kind")
392 }
393
394 func (v Value) group() []Attr {
395 return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num)
396 }
397
398
399
400
401 func (v Value) Equal(w Value) bool {
402 k1 := v.Kind()
403 k2 := w.Kind()
404 if k1 != k2 {
405 return false
406 }
407 switch k1 {
408 case KindInt64, KindUint64, KindBool, KindDuration:
409 return v.num == w.num
410 case KindString:
411 return v.str() == w.str()
412 case KindFloat64:
413 return v.float() == w.float()
414 case KindTime:
415 return v.time().Equal(w.time())
416 case KindAny, KindLogValuer:
417 return v.any == w.any
418 case KindGroup:
419 return slices.EqualFunc(v.group(), w.group(), Attr.Equal)
420 default:
421 panic(fmt.Sprintf("bad kind: %s", k1))
422 }
423 }
424
425
426 func (v Value) isEmptyGroup() bool {
427 if v.Kind() != KindGroup {
428 return false
429 }
430
431
432
433 return len(v.group()) == 0
434 }
435
436
437
438 func (v Value) append(dst []byte) []byte {
439 switch v.Kind() {
440 case KindString:
441 return append(dst, v.str()...)
442 case KindInt64:
443 return strconv.AppendInt(dst, int64(v.num), 10)
444 case KindUint64:
445 return strconv.AppendUint(dst, v.num, 10)
446 case KindFloat64:
447 return strconv.AppendFloat(dst, v.float(), 'g', -1, 64)
448 case KindBool:
449 return strconv.AppendBool(dst, v.bool())
450 case KindDuration:
451 return append(dst, v.duration().String()...)
452 case KindTime:
453 return append(dst, v.time().String()...)
454 case KindGroup:
455 return fmt.Append(dst, v.group())
456 case KindAny, KindLogValuer:
457 return fmt.Append(dst, v.any)
458 default:
459 panic(fmt.Sprintf("bad kind: %s", v.Kind()))
460 }
461 }
462
463
464
465
466
467 type LogValuer interface {
468 LogValue() Value
469 }
470
471 const maxLogValues = 100
472
473
474
475
476
477
478
479
480 func (v Value) Resolve() (rv Value) {
481 orig := v
482 defer func() {
483 if r := recover(); r != nil {
484 rv = AnyValue(fmt.Errorf("LogValue panicked\n%s", stack(3, 5)))
485 }
486 }()
487
488 for i := 0; i < maxLogValues; i++ {
489 if v.Kind() != KindLogValuer {
490 return v
491 }
492 v = v.LogValuer().LogValue()
493 }
494 err := fmt.Errorf("LogValue called too many times on Value of type %T", orig.Any())
495 return AnyValue(err)
496 }
497
498 func stack(skip, nFrames int) string {
499 pcs := make([]uintptr, nFrames+1)
500 n := runtime.Callers(skip+1, pcs)
501 if n == 0 {
502 return "(no stack)"
503 }
504 frames := runtime.CallersFrames(pcs[:n])
505 var b strings.Builder
506 i := 0
507 for {
508 frame, more := frames.Next()
509 fmt.Fprintf(&b, "called from %s (%s:%d)\n", frame.Function, frame.File, frame.Line)
510 if !more {
511 break
512 }
513 i++
514 if i >= nFrames {
515 fmt.Fprintf(&b, "(rest of stack elided)\n")
516 break
517 }
518 }
519 return b.String()
520 }
521
View as plain text