package attribute
import (
"encoding/base64"
"encoding/json"
"fmt"
"math"
"reflect"
"strconv"
"strings"
"unicode/utf8"
attribute "go.opentelemetry.io/otel/attribute/internal"
)
type Type int
type Value struct {
vtype Type
numeric uint64
stringly string
slice any
}
const (
EMPTY Type = iota
BOOL
INT64
FLOAT64
STRING
BOOLSLICE
INT64SLICE
FLOAT64SLICE
STRINGSLICE
BYTESLICE
SLICE
INVALID = EMPTY
)
func BoolValue (v bool ) Value {
return Value {
vtype : BOOL ,
numeric : boolToRaw (v ),
}
}
func BoolSliceValue (v []bool ) Value {
return Value {vtype : BOOLSLICE , slice : attribute .SliceValue (v )}
}
func IntValue (v int ) Value {
return Int64Value (int64 (v ))
}
func IntSliceValue (v []int ) Value {
val := Value {vtype : INT64SLICE }
switch len (v ) {
case 0 :
val .slice = [0 ]int64 {}
case 1 :
val .slice = [1 ]int64 {int64 (v [0 ])}
case 2 :
val .slice = [2 ]int64 {int64 (v [0 ]), int64 (v [1 ])}
case 3 :
val .slice = [3 ]int64 {int64 (v [0 ]), int64 (v [1 ]), int64 (v [2 ])}
default :
cp := make ([]int64 , len (v ))
for i , val := range v {
cp [i ] = int64 (val )
}
val .slice = attribute .SliceValue (cp )
}
return val
}
func Int64Value (v int64 ) Value {
return Value {
vtype : INT64 ,
numeric : int64ToRaw (v ),
}
}
func Int64SliceValue (v []int64 ) Value {
return Value {vtype : INT64SLICE , slice : attribute .SliceValue (v )}
}
func Float64Value (v float64 ) Value {
return Value {
vtype : FLOAT64 ,
numeric : float64ToRaw (v ),
}
}
func Float64SliceValue (v []float64 ) Value {
return Value {vtype : FLOAT64SLICE , slice : attribute .SliceValue (v )}
}
func StringValue (v string ) Value {
return Value {
vtype : STRING ,
stringly : v ,
}
}
func StringSliceValue (v []string ) Value {
return Value {vtype : STRINGSLICE , slice : attribute .SliceValue (v )}
}
func ByteSliceValue (v []byte ) Value {
return Value {
vtype : BYTESLICE ,
stringly : string (v ),
}
}
func SliceValue (v ...Value ) Value {
return Value {vtype : SLICE , slice : sliceValue (v )}
}
func (v Value ) Type () Type {
return v .vtype
}
func (v Value ) AsBool () bool {
return rawToBool (v .numeric )
}
func (v Value ) AsBoolSlice () []bool {
if v .vtype != BOOLSLICE {
return nil
}
return v .asBoolSlice ()
}
func (v Value ) asBoolSlice () []bool {
return attribute .AsSlice [bool ](v .slice )
}
func (v Value ) AsInt64 () int64 {
return rawToInt64 (v .numeric )
}
func (v Value ) AsInt64Slice () []int64 {
if v .vtype != INT64SLICE {
return nil
}
return v .asInt64Slice ()
}
func (v Value ) asInt64Slice () []int64 {
return attribute .AsSlice [int64 ](v .slice )
}
func (v Value ) AsFloat64 () float64 {
return rawToFloat64 (v .numeric )
}
func (v Value ) AsFloat64Slice () []float64 {
if v .vtype != FLOAT64SLICE {
return nil
}
return v .asFloat64Slice ()
}
func (v Value ) asFloat64Slice () []float64 {
return attribute .AsSlice [float64 ](v .slice )
}
func (v Value ) AsString () string {
return v .stringly
}
func (v Value ) AsStringSlice () []string {
if v .vtype != STRINGSLICE {
return nil
}
return v .asStringSlice ()
}
func (v Value ) asStringSlice () []string {
return attribute .AsSlice [string ](v .slice )
}
func (v Value ) AsSlice () []Value {
if v .vtype != SLICE {
return nil
}
return v .asSlice ()
}
func (v Value ) asSlice () []Value {
switch vals := v .slice .(type ) {
case [0 ]Value :
return []Value {}
case [1 ]Value :
return []Value {vals [0 ]}
case [2 ]Value :
return []Value {vals [0 ], vals [1 ]}
case [3 ]Value :
return []Value {vals [0 ], vals [1 ], vals [2 ]}
case [4 ]Value :
return []Value {vals [0 ], vals [1 ], vals [2 ], vals [3 ]}
case [5 ]Value :
return []Value {vals [0 ], vals [1 ], vals [2 ], vals [3 ], vals [4 ]}
default :
return asValueSliceReflect (v .slice )
}
}
func asValueSliceReflect (v any ) []Value {
rv := reflect .ValueOf (v )
if !rv .IsValid () || rv .Kind () != reflect .Array || rv .Type ().Elem () != reflect .TypeFor [Value ]() {
return nil
}
cpy := make ([]Value , rv .Len ())
if len (cpy ) > 0 {
_ = reflect .Copy (reflect .ValueOf (cpy ), rv )
}
return cpy
}
func (v Value ) AsByteSlice () []byte {
if v .vtype != BYTESLICE {
return nil
}
return v .asByteSlice ()
}
func (v Value ) asByteSlice () []byte {
return []byte (v .stringly )
}
type unknownValueType struct {}
func (v Value ) AsInterface () any {
switch v .Type () {
case BOOL :
return v .AsBool ()
case BOOLSLICE :
return v .asBoolSlice ()
case INT64 :
return v .AsInt64 ()
case INT64SLICE :
return v .asInt64Slice ()
case FLOAT64 :
return v .AsFloat64 ()
case FLOAT64SLICE :
return v .asFloat64Slice ()
case STRING :
return v .stringly
case STRINGSLICE :
return v .asStringSlice ()
case BYTESLICE :
return v .asByteSlice ()
case SLICE :
return v .asSlice ()
case EMPTY :
return nil
}
return unknownValueType {}
}
func (v Value ) String () string {
switch v .Type () {
case BOOL :
return strconv .FormatBool (v .AsBool ())
case BOOLSLICE :
return formatBoolSliceValue (v .slice )
case INT64 :
return strconv .FormatInt (v .AsInt64 (), 10 )
case INT64SLICE :
return formatInt64SliceValue (v .slice )
case FLOAT64 :
return formatFloat64 (v .AsFloat64 ())
case FLOAT64SLICE :
return formatFloat64SliceValue (v .slice )
case STRING :
return v .stringly
case STRINGSLICE :
return formatStringSliceValue (v .slice )
case BYTESLICE :
return formatByteSlice (v .stringly )
case SLICE :
return formatValueSliceValue (v .slice )
case EMPTY :
return ""
default :
return "unknown"
}
}
func (v Value ) Emit () string {
switch v .Type () {
case BOOLSLICE :
return fmt .Sprint (v .asBoolSlice ())
case BOOL :
return strconv .FormatBool (v .AsBool ())
case INT64SLICE :
j , err := json .Marshal (v .asInt64Slice ())
if err != nil {
return fmt .Sprintf ("invalid: %v" , v .asInt64Slice ())
}
return string (j )
case INT64 :
return strconv .FormatInt (v .AsInt64 (), 10 )
case FLOAT64SLICE :
j , err := json .Marshal (v .asFloat64Slice ())
if err != nil {
return fmt .Sprintf ("invalid: %v" , v .asFloat64Slice ())
}
return string (j )
case FLOAT64 :
return fmt .Sprint (v .AsFloat64 ())
case STRINGSLICE :
j , err := json .Marshal (v .asStringSlice ())
if err != nil {
return fmt .Sprintf ("invalid: %v" , v .asStringSlice ())
}
return string (j )
case STRING :
return v .stringly
case BYTESLICE :
return formatByteSlice (v .stringly )
case SLICE :
return formatValueSliceValue (v .slice )
case EMPTY :
return ""
default :
return "unknown"
}
}
const (
jsonArrayBracketsLen = len ("[]" )
boolArrayElemMaxLen = len ("false" )
int64ArrayElemMaxLen = len ("-9223372036854775808" )
float64ArrayElemMaxLen = len ("-1.7976931348623157e+308" )
commaLen = len ("," )
)
func sliceValue (v []Value ) any {
switch len (v ) {
case 0 :
return [0 ]Value {}
case 1 :
return [1 ]Value {v [0 ]}
case 2 :
return [2 ]Value {v [0 ], v [1 ]}
case 3 :
return [3 ]Value {v [0 ], v [1 ], v [2 ]}
case 4 :
return [4 ]Value {v [0 ], v [1 ], v [2 ], v [3 ]}
case 5 :
return [5 ]Value {v [0 ], v [1 ], v [2 ], v [3 ], v [4 ]}
default :
return sliceValueReflect (v )
}
}
func sliceValueReflect (v []Value ) any {
cp := reflect .New (reflect .ArrayOf (len (v ), reflect .TypeFor [Value ]())).Elem ()
reflect .Copy (cp , reflect .ValueOf (v ))
return cp .Interface ()
}
func formatBoolSliceValue (v any ) string {
switch vals := v .(type ) {
case [0 ]bool :
return "[]"
case [1 ]bool :
return formatBoolSlice (vals [:])
case [2 ]bool :
return formatBoolSlice (vals [:])
case [3 ]bool :
return formatBoolSlice (vals [:])
default :
return formatBoolSliceReflect (v )
}
}
func formatBoolSlice (vals []bool ) string {
var b strings .Builder
appendBoolSlice (&b , vals )
return b .String ()
}
func formatBoolSliceReflect (v any ) string {
var b strings .Builder
appendBoolSliceReflect (&b , reflect .ValueOf (v ))
return b .String ()
}
func appendBoolSliceValue (dst *strings .Builder , v any ) {
switch vals := v .(type ) {
case [0 ]bool :
_, _ = dst .WriteString ("[]" )
case [1 ]bool :
appendBoolSlice (dst , vals [:])
case [2 ]bool :
appendBoolSlice (dst , vals [:])
case [3 ]bool :
appendBoolSlice (dst , vals [:])
default :
appendBoolSliceReflect (dst , reflect .ValueOf (v ))
}
}
func appendBoolSlice (dst *strings .Builder , vals []bool ) {
dst .Grow (jsonArrayBracketsLen + len (vals )*(boolArrayElemMaxLen +commaLen ))
_ = dst .WriteByte ('[' )
for i , val := range vals {
if i > 0 {
_ = dst .WriteByte (',' )
}
if val {
_, _ = dst .WriteString ("true" )
} else {
_, _ = dst .WriteString ("false" )
}
}
_ = dst .WriteByte (']' )
}
func appendBoolSliceReflect (dst *strings .Builder , rv reflect .Value ) {
dst .Grow (jsonArrayBracketsLen + rv .Len ()*(boolArrayElemMaxLen +commaLen ))
_ = dst .WriteByte ('[' )
for i := 0 ; i < rv .Len (); i ++ {
if i > 0 {
_ = dst .WriteByte (',' )
}
if rv .Index (i ).Bool () {
_, _ = dst .WriteString ("true" )
} else {
_, _ = dst .WriteString ("false" )
}
}
_ = dst .WriteByte (']' )
}
func formatInt64SliceValue (v any ) string {
switch vals := v .(type ) {
case [0 ]int64 :
return "[]"
case [1 ]int64 :
return formatInt64Slice (vals [:])
case [2 ]int64 :
return formatInt64Slice (vals [:])
case [3 ]int64 :
return formatInt64Slice (vals [:])
default :
return formatInt64SliceReflect (v )
}
}
func formatInt64Slice (vals []int64 ) string {
var b strings .Builder
appendInt64Slice (&b , vals )
return b .String ()
}
func formatInt64SliceReflect (v any ) string {
var b strings .Builder
appendInt64SliceReflect (&b , reflect .ValueOf (v ))
return b .String ()
}
func appendInt64SliceValue (dst *strings .Builder , v any ) {
switch vals := v .(type ) {
case [0 ]int64 :
_, _ = dst .WriteString ("[]" )
case [1 ]int64 :
appendInt64Slice (dst , vals [:])
case [2 ]int64 :
appendInt64Slice (dst , vals [:])
case [3 ]int64 :
appendInt64Slice (dst , vals [:])
default :
appendInt64SliceReflect (dst , reflect .ValueOf (v ))
}
}
func appendInt64Slice (dst *strings .Builder , vals []int64 ) {
dst .Grow (jsonArrayBracketsLen + len (vals )*(int64ArrayElemMaxLen +commaLen ))
_ = dst .WriteByte ('[' )
var buf [int64ArrayElemMaxLen ]byte
for i , val := range vals {
if i > 0 {
_ = dst .WriteByte (',' )
}
out := strconv .AppendInt (buf [:0 ], val , 10 )
_, _ = dst .Write (out )
}
_ = dst .WriteByte (']' )
}
func appendInt64SliceReflect (dst *strings .Builder , rv reflect .Value ) {
dst .Grow (jsonArrayBracketsLen + rv .Len ()*(int64ArrayElemMaxLen +commaLen ))
_ = dst .WriteByte ('[' )
var scratch [int64ArrayElemMaxLen ]byte
for i := 0 ; i < rv .Len (); i ++ {
if i > 0 {
_ = dst .WriteByte (',' )
}
out := strconv .AppendInt (scratch [:0 ], rv .Index (i ).Int (), 10 )
_, _ = dst .Write (out )
}
_ = dst .WriteByte (']' )
}
func formatFloat64 (v float64 ) string {
switch {
case math .IsNaN (v ):
return "NaN"
case math .IsInf (v , 1 ):
return "Infinity"
case math .IsInf (v , -1 ):
return "-Infinity"
default :
return strconv .FormatFloat (v , 'g' , -1 , 64 )
}
}
func formatFloat64SliceValue (v any ) string {
switch vals := v .(type ) {
case [0 ]float64 :
return "[]"
case [1 ]float64 :
return formatFloat64Slice (vals [:])
case [2 ]float64 :
return formatFloat64Slice (vals [:])
case [3 ]float64 :
return formatFloat64Slice (vals [:])
default :
return formatFloat64SliceReflect (v )
}
}
func formatFloat64Slice (vals []float64 ) string {
var b strings .Builder
appendFloat64Slice (&b , vals )
return b .String ()
}
func formatFloat64SliceReflect (v any ) string {
var b strings .Builder
appendFloat64SliceReflect (&b , reflect .ValueOf (v ))
return b .String ()
}
func appendFloat64SliceValue (dst *strings .Builder , v any ) {
switch vals := v .(type ) {
case [0 ]float64 :
_, _ = dst .WriteString ("[]" )
case [1 ]float64 :
appendFloat64Slice (dst , vals [:])
case [2 ]float64 :
appendFloat64Slice (dst , vals [:])
case [3 ]float64 :
appendFloat64Slice (dst , vals [:])
default :
appendFloat64SliceReflect (dst , reflect .ValueOf (v ))
}
}
func appendFloat64Slice (dst *strings .Builder , vals []float64 ) {
dst .Grow (jsonArrayBracketsLen + len (vals )*(float64ArrayElemMaxLen +commaLen ))
_ = dst .WriteByte ('[' )
var buf [float64ArrayElemMaxLen ]byte
for i , val := range vals {
if i > 0 {
_ = dst .WriteByte (',' )
}
switch {
case math .IsNaN (val ):
_, _ = dst .WriteString (`"NaN"` )
case math .IsInf (val , 1 ):
_, _ = dst .WriteString (`"Infinity"` )
case math .IsInf (val , -1 ):
_, _ = dst .WriteString (`"-Infinity"` )
default :
out := strconv .AppendFloat (buf [:0 ], val , 'g' , -1 , 64 )
_, _ = dst .Write (out )
}
}
_ = dst .WriteByte (']' )
}
func appendFloat64SliceReflect (dst *strings .Builder , rv reflect .Value ) {
dst .Grow (jsonArrayBracketsLen + rv .Len ()*(float64ArrayElemMaxLen +commaLen ))
_ = dst .WriteByte ('[' )
var scratch [float64ArrayElemMaxLen ]byte
for i := 0 ; i < rv .Len (); i ++ {
if i > 0 {
_ = dst .WriteByte (',' )
}
val := rv .Index (i ).Float ()
switch {
case math .IsNaN (val ):
_, _ = dst .WriteString (`"NaN"` )
case math .IsInf (val , 1 ):
_, _ = dst .WriteString (`"Infinity"` )
case math .IsInf (val , -1 ):
_, _ = dst .WriteString (`"-Infinity"` )
default :
out := strconv .AppendFloat (scratch [:0 ], val , 'g' , -1 , 64 )
_, _ = dst .Write (out )
}
}
_ = dst .WriteByte (']' )
}
func formatStringSliceValue (v any ) string {
switch vals := v .(type ) {
case [0 ]string :
return "[]"
case [1 ]string :
return formatStringSlice (vals [:])
case [2 ]string :
return formatStringSlice (vals [:])
case [3 ]string :
return formatStringSlice (vals [:])
default :
return formatStringSliceReflect (v )
}
}
func formatStringSlice (vals []string ) string {
var b strings .Builder
appendStringSlice (&b , vals )
return b .String ()
}
func formatStringSliceReflect (v any ) string {
var b strings .Builder
appendStringSliceReflect (&b , reflect .ValueOf (v ))
return b .String ()
}
func appendStringSliceValue (dst *strings .Builder , v any ) {
switch vals := v .(type ) {
case [0 ]string :
_, _ = dst .WriteString ("[]" )
case [1 ]string :
appendStringSlice (dst , vals [:])
case [2 ]string :
appendStringSlice (dst , vals [:])
case [3 ]string :
appendStringSlice (dst , vals [:])
default :
appendStringSliceReflect (dst , reflect .ValueOf (v ))
}
}
func appendStringSlice (dst *strings .Builder , vals []string ) {
size := jsonArrayBracketsLen
for _ , val := range vals {
size += len (val ) + commaLen + 2
}
dst .Grow (size )
_ = dst .WriteByte ('[' )
for i , val := range vals {
if i > 0 {
_ = dst .WriteByte (',' )
}
appendJSONString (dst , val )
}
_ = dst .WriteByte (']' )
}
func appendStringSliceReflect (dst *strings .Builder , rv reflect .Value ) {
size := jsonArrayBracketsLen
for i := 0 ; i < rv .Len (); i ++ {
size += len (rv .Index (i ).String ()) + commaLen + 2
}
dst .Grow (size )
_ = dst .WriteByte ('[' )
for i := 0 ; i < rv .Len (); i ++ {
if i > 0 {
_ = dst .WriteByte (',' )
}
appendJSONString (dst , rv .Index (i ).String ())
}
_ = dst .WriteByte (']' )
}
func formatByteSlice (v string ) string {
var b strings .Builder
appendBase64 (&b , v )
return b .String ()
}
func formatValueSliceValue (v any ) string {
switch vals := v .(type ) {
case [0 ]Value :
return "[]"
case [1 ]Value :
return formatValueSlice (vals [:])
case [2 ]Value :
return formatValueSlice (vals [:])
case [3 ]Value :
return formatValueSlice (vals [:])
case [4 ]Value :
return formatValueSlice (vals [:])
case [5 ]Value :
return formatValueSlice (vals [:])
default :
return formatValueSliceReflect (v )
}
}
func formatValueSlice (vals []Value ) string {
var b strings .Builder
appendValueSlice (&b , vals )
return b .String ()
}
func formatValueSliceReflect (v any ) string {
var b strings .Builder
appendValueSliceReflect (&b , reflect .ValueOf (v ))
return b .String ()
}
func appendValueSliceValue (dst *strings .Builder , v any ) {
switch vals := v .(type ) {
case [0 ]Value :
_, _ = dst .WriteString ("[]" )
case [1 ]Value :
appendValueSlice (dst , vals [:])
case [2 ]Value :
appendValueSlice (dst , vals [:])
case [3 ]Value :
appendValueSlice (dst , vals [:])
case [4 ]Value :
appendValueSlice (dst , vals [:])
case [5 ]Value :
appendValueSlice (dst , vals [:])
default :
appendValueSliceReflect (dst , reflect .ValueOf (v ))
}
}
func appendValueSlice (dst *strings .Builder , vals []Value ) {
dst .Grow (jsonArrayBracketsLen + len (vals )*commaLen + len (vals )*10 )
_ = dst .WriteByte ('[' )
for i , val := range vals {
if i > 0 {
_ = dst .WriteByte (',' )
}
appendJSONValue (dst , val )
}
_ = dst .WriteByte (']' )
}
func appendValueSliceReflect (dst *strings .Builder , rv reflect .Value ) {
dst .Grow (jsonArrayBracketsLen + rv .Len ()*commaLen + rv .Len ()*10 )
_ = dst .WriteByte ('[' )
for i := 0 ; i < rv .Len (); i ++ {
if i > 0 {
_ = dst .WriteByte (',' )
}
appendJSONValue (dst , rv .Index (i ).Interface ().(Value ))
}
_ = dst .WriteByte (']' )
}
func appendJSONValue (dst *strings .Builder , v Value ) {
switch v .Type () {
case BOOL :
if v .AsBool () {
_, _ = dst .WriteString ("true" )
} else {
_, _ = dst .WriteString ("false" )
}
case BOOLSLICE :
appendBoolSliceValue (dst , v .slice )
case INT64 :
var buf [int64ArrayElemMaxLen ]byte
out := strconv .AppendInt (buf [:0 ], v .AsInt64 (), 10 )
_, _ = dst .Write (out )
case INT64SLICE :
appendInt64SliceValue (dst , v .slice )
case FLOAT64 :
val := v .AsFloat64 ()
switch {
case math .IsNaN (val ):
appendJSONString (dst , "NaN" )
case math .IsInf (val , 1 ):
appendJSONString (dst , "Infinity" )
case math .IsInf (val , -1 ):
appendJSONString (dst , "-Infinity" )
default :
var buf [float64ArrayElemMaxLen ]byte
out := strconv .AppendFloat (buf [:0 ], val , 'g' , -1 , 64 )
_, _ = dst .Write (out )
}
case FLOAT64SLICE :
appendFloat64SliceValue (dst , v .slice )
case STRING :
appendJSONString (dst , v .stringly )
case STRINGSLICE :
appendStringSliceValue (dst , v .slice )
case BYTESLICE :
_ = dst .WriteByte ('"' )
appendBase64 (dst , v .stringly )
_ = dst .WriteByte ('"' )
case SLICE :
appendValueSliceValue (dst , v .slice )
case EMPTY :
_, _ = dst .WriteString ("null" )
default :
appendJSONString (dst , "unknown" )
}
}
func appendJSONString (dst *strings .Builder , s string ) {
const hex = "0123456789abcdef"
_ = dst .WriteByte ('"' )
start := 0
for i := 0 ; i < len (s ); {
if c := s [i ]; c < utf8 .RuneSelf {
if c >= 0x20 && c != '\\' && c != '"' {
i ++
continue
}
if start < i {
_, _ = dst .WriteString (s [start :i ])
}
switch c {
case '\\' , '"' :
_ = dst .WriteByte ('\\' )
_ = dst .WriteByte (c )
case '\b' :
_, _ = dst .WriteString (`\b` )
case '\f' :
_, _ = dst .WriteString (`\f` )
case '\n' :
_, _ = dst .WriteString (`\n` )
case '\r' :
_, _ = dst .WriteString (`\r` )
case '\t' :
_, _ = dst .WriteString (`\t` )
default :
_, _ = dst .WriteString (`\u00` )
_ = dst .WriteByte (hex [c >>4 ])
_ = dst .WriteByte (hex [c &0x0f ])
}
i ++
start = i
continue
}
r , size := utf8 .DecodeRuneInString (s [i :])
if r == utf8 .RuneError && size == 1 {
if start < i {
_, _ = dst .WriteString (s [start :i ])
}
_, _ = dst .WriteString (`\ufffd` )
i ++
start = i
continue
}
if r == '\u2028' || r == '\u2029' {
if start < i {
_, _ = dst .WriteString (s [start :i ])
}
_, _ = dst .WriteString (`\u202` )
_ = dst .WriteByte (hex [r &0x0f ])
i += size
start = i
continue
}
i += size
}
if start < len (s ) {
_, _ = dst .WriteString (s [start :])
}
_ = dst .WriteByte ('"' )
}
func appendBase64 (dst *strings .Builder , s string ) {
const encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
dst .Grow (base64 .StdEncoding .EncodedLen (len (s )))
i := 0
for ; i +2 < len (s ); i += 3 {
n := uint32 (s [i ])<<16 | uint32 (s [i +1 ])<<8 | uint32 (s [i +2 ])
_ = dst .WriteByte (encode [n >>18 &0x3f ])
_ = dst .WriteByte (encode [n >>12 &0x3f ])
_ = dst .WriteByte (encode [n >>6 &0x3f ])
_ = dst .WriteByte (encode [n &0x3f ])
}
switch len (s ) - i {
case 1 :
n := uint32 (s [i ]) << 16
_ = dst .WriteByte (encode [n >>18 &0x3f ])
_ = dst .WriteByte (encode [n >>12 &0x3f ])
_ = dst .WriteByte ('=' )
_ = dst .WriteByte ('=' )
case 2 :
n := uint32 (s [i ])<<16 | uint32 (s [i +1 ])<<8
_ = dst .WriteByte (encode [n >>18 &0x3f ])
_ = dst .WriteByte (encode [n >>12 &0x3f ])
_ = dst .WriteByte (encode [n >>6 &0x3f ])
_ = dst .WriteByte ('=' )
}
}
func (v Value ) MarshalJSON () ([]byte , error ) {
var jsonVal struct {
Type string
Value any
}
jsonVal .Type = v .Type ().String ()
jsonVal .Value = v .AsInterface ()
return json .Marshal (jsonVal )
}
The pages are generated with Golds v0.8.4 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .