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, timeTime:
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 type (
143
144
145 timeLocation *time.Location
146
147
148 timeTime time.Time
149 )
150
151
152
153 func TimeValue(v time.Time) Value {
154 if v.IsZero() {
155
156
157
158
159 return Value{any: timeLocation(nil)}
160 }
161 nsec := v.UnixNano()
162 t := time.Unix(0, nsec)
163 if v.Equal(t) {
164
165 return Value{num: uint64(nsec), any: timeLocation(v.Location())}
166 }
167
168
169 return Value{any: timeTime(v.Round(0))}
170 }
171
172
173 func DurationValue(v time.Duration) Value {
174 return Value{num: uint64(v.Nanoseconds()), any: KindDuration}
175 }
176
177
178
179 func GroupValue(as ...Attr) Value {
180
181
182
183 if n := countEmptyGroups(as); n > 0 {
184 as2 := make([]Attr, 0, len(as)-n)
185 for _, a := range as {
186 if !a.Value.isEmptyGroup() {
187 as2 = append(as2, a)
188 }
189 }
190 as = as2
191 }
192 return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))}
193 }
194
195
196 func countEmptyGroups(as []Attr) int {
197 n := 0
198 for _, a := range as {
199 if a.Value.isEmptyGroup() {
200 n++
201 }
202 }
203 return n
204 }
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221 func AnyValue(v any) Value {
222 switch v := v.(type) {
223 case string:
224 return StringValue(v)
225 case int:
226 return Int64Value(int64(v))
227 case uint:
228 return Uint64Value(uint64(v))
229 case int64:
230 return Int64Value(v)
231 case uint64:
232 return Uint64Value(v)
233 case bool:
234 return BoolValue(v)
235 case time.Duration:
236 return DurationValue(v)
237 case time.Time:
238 return TimeValue(v)
239 case uint8:
240 return Uint64Value(uint64(v))
241 case uint16:
242 return Uint64Value(uint64(v))
243 case uint32:
244 return Uint64Value(uint64(v))
245 case uintptr:
246 return Uint64Value(uint64(v))
247 case int8:
248 return Int64Value(int64(v))
249 case int16:
250 return Int64Value(int64(v))
251 case int32:
252 return Int64Value(int64(v))
253 case float64:
254 return Float64Value(v)
255 case float32:
256 return Float64Value(float64(v))
257 case []Attr:
258 return GroupValue(v...)
259 case Kind:
260 return Value{any: kind(v)}
261 case Value:
262 return v
263 default:
264 return Value{any: v}
265 }
266 }
267
268
269
270
271 func (v Value) Any() any {
272 switch v.Kind() {
273 case KindAny:
274 if k, ok := v.any.(kind); ok {
275 return Kind(k)
276 }
277 return v.any
278 case KindLogValuer:
279 return v.any
280 case KindGroup:
281 return v.group()
282 case KindInt64:
283 return int64(v.num)
284 case KindUint64:
285 return v.num
286 case KindFloat64:
287 return v.float()
288 case KindString:
289 return v.str()
290 case KindBool:
291 return v.bool()
292 case KindDuration:
293 return v.duration()
294 case KindTime:
295 return v.time()
296 default:
297 panic(fmt.Sprintf("bad kind: %s", v.Kind()))
298 }
299 }
300
301
302
303
304 func (v Value) String() string {
305 if sp, ok := v.any.(stringptr); ok {
306 return unsafe.String(sp, v.num)
307 }
308 var buf []byte
309 return string(v.append(buf))
310 }
311
312 func (v Value) str() string {
313 return unsafe.String(v.any.(stringptr), v.num)
314 }
315
316
317
318 func (v Value) Int64() int64 {
319 if g, w := v.Kind(), KindInt64; g != w {
320 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
321 }
322 return int64(v.num)
323 }
324
325
326
327 func (v Value) Uint64() uint64 {
328 if g, w := v.Kind(), KindUint64; g != w {
329 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
330 }
331 return v.num
332 }
333
334
335
336 func (v Value) Bool() bool {
337 if g, w := v.Kind(), KindBool; g != w {
338 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
339 }
340 return v.bool()
341 }
342
343 func (v Value) bool() bool {
344 return v.num == 1
345 }
346
347
348
349 func (v Value) Duration() time.Duration {
350 if g, w := v.Kind(), KindDuration; g != w {
351 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
352 }
353
354 return v.duration()
355 }
356
357 func (v Value) duration() time.Duration {
358 return time.Duration(int64(v.num))
359 }
360
361
362
363 func (v Value) Float64() float64 {
364 if g, w := v.Kind(), KindFloat64; g != w {
365 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
366 }
367
368 return v.float()
369 }
370
371 func (v Value) float() float64 {
372 return math.Float64frombits(v.num)
373 }
374
375
376
377 func (v Value) Time() time.Time {
378 if g, w := v.Kind(), KindTime; g != w {
379 panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
380 }
381 return v.time()
382 }
383
384
385 func (v Value) time() time.Time {
386 switch a := v.any.(type) {
387 case timeLocation:
388 if a == nil {
389 return time.Time{}
390 }
391 return time.Unix(0, int64(v.num)).In(a)
392 case timeTime:
393 return time.Time(a)
394 default:
395 panic(fmt.Sprintf("bad time type %T", v.any))
396 }
397 }
398
399
400
401 func (v Value) LogValuer() LogValuer {
402 return v.any.(LogValuer)
403 }
404
405
406
407 func (v Value) Group() []Attr {
408 if sp, ok := v.any.(groupptr); ok {
409 return unsafe.Slice((*Attr)(sp), v.num)
410 }
411 panic("Group: bad kind")
412 }
413
414 func (v Value) group() []Attr {
415 return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num)
416 }
417
418
419
420
421 func (v Value) Equal(w Value) bool {
422 k1 := v.Kind()
423 k2 := w.Kind()
424 if k1 != k2 {
425 return false
426 }
427 switch k1 {
428 case KindInt64, KindUint64, KindBool, KindDuration:
429 return v.num == w.num
430 case KindString:
431 return v.str() == w.str()
432 case KindFloat64:
433 return v.float() == w.float()
434 case KindTime:
435 return v.time().Equal(w.time())
436 case KindAny, KindLogValuer:
437 return v.any == w.any
438 case KindGroup:
439 return slices.EqualFunc(v.group(), w.group(), Attr.Equal)
440 default:
441 panic(fmt.Sprintf("bad kind: %s", k1))
442 }
443 }
444
445
446 func (v Value) isEmptyGroup() bool {
447 if v.Kind() != KindGroup {
448 return false
449 }
450
451
452
453 return len(v.group()) == 0
454 }
455
456
457
458 func (v Value) append(dst []byte) []byte {
459 switch v.Kind() {
460 case KindString:
461 return append(dst, v.str()...)
462 case KindInt64:
463 return strconv.AppendInt(dst, int64(v.num), 10)
464 case KindUint64:
465 return strconv.AppendUint(dst, v.num, 10)
466 case KindFloat64:
467 return strconv.AppendFloat(dst, v.float(), 'g', -1, 64)
468 case KindBool:
469 return strconv.AppendBool(dst, v.bool())
470 case KindDuration:
471 return append(dst, v.duration().String()...)
472 case KindTime:
473 return append(dst, v.time().String()...)
474 case KindGroup:
475 return fmt.Append(dst, v.group())
476 case KindAny, KindLogValuer:
477 return fmt.Append(dst, v.any)
478 default:
479 panic(fmt.Sprintf("bad kind: %s", v.Kind()))
480 }
481 }
482
483
484
485
486
487 type LogValuer interface {
488 LogValue() Value
489 }
490
491 const maxLogValues = 100
492
493
494
495
496
497
498
499
500 func (v Value) Resolve() (rv Value) {
501 orig := v
502 defer func() {
503 if r := recover(); r != nil {
504 rv = AnyValue(fmt.Errorf("LogValue panicked\n%s", stack(3, 5)))
505 }
506 }()
507
508 for i := 0; i < maxLogValues; i++ {
509 if v.Kind() != KindLogValuer {
510 return v
511 }
512 v = v.LogValuer().LogValue()
513 }
514 err := fmt.Errorf("LogValue called too many times on Value of type %T", orig.Any())
515 return AnyValue(err)
516 }
517
518 func stack(skip, nFrames int) string {
519 pcs := make([]uintptr, nFrames+1)
520 n := runtime.Callers(skip+1, pcs)
521 if n == 0 {
522 return "(no stack)"
523 }
524 frames := runtime.CallersFrames(pcs[:n])
525 var b strings.Builder
526 i := 0
527 for {
528 frame, more := frames.Next()
529 fmt.Fprintf(&b, "called from %s (%s:%d)\n", frame.Function, frame.File, frame.Line)
530 if !more {
531 break
532 }
533 i++
534 if i >= nFrames {
535 fmt.Fprintf(&b, "(rest of stack elided)\n")
536 break
537 }
538 }
539 return b.String()
540 }
541
View as plain text