github.com/goccy/go-json@v0.10.3-0.20240509105655-5e2ae3f23c1d/internal/encoder/vm_color_indent/util.go (about)

     1  package vm_color_indent
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"unsafe"
     7  
     8  	"github.com/goccy/go-json/internal/encoder"
     9  	"github.com/goccy/go-json/internal/runtime"
    10  )
    11  
    12  const uintptrSize = 4 << (^uintptr(0) >> 63)
    13  
    14  var (
    15  	appendIndent        = encoder.AppendIndent
    16  	appendStructEnd     = encoder.AppendStructEndIndent
    17  	errUnsupportedValue = encoder.ErrUnsupportedValue
    18  	errUnsupportedFloat = encoder.ErrUnsupportedFloat
    19  	mapiterinit         = encoder.MapIterInit
    20  	mapiterkey          = encoder.MapIterKey
    21  	mapitervalue        = encoder.MapIterValue
    22  	mapiternext         = encoder.MapIterNext
    23  	maplen              = encoder.MapLen
    24  )
    25  
    26  type emptyInterface struct {
    27  	typ *runtime.Type
    28  	ptr unsafe.Pointer
    29  }
    30  
    31  type nonEmptyInterface struct {
    32  	itab *struct {
    33  		ityp *runtime.Type // static interface type
    34  		typ  *runtime.Type // dynamic concrete type
    35  		// unused fields...
    36  	}
    37  	ptr unsafe.Pointer
    38  }
    39  
    40  func errUnimplementedOp(op encoder.OpType) error {
    41  	return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op)
    42  }
    43  
    44  func load(base uintptr, idx uint32) uintptr {
    45  	addr := base + uintptr(idx)
    46  	return **(**uintptr)(unsafe.Pointer(&addr))
    47  }
    48  
    49  func store(base uintptr, idx uint32, p uintptr) {
    50  	addr := base + uintptr(idx)
    51  	**(**uintptr)(unsafe.Pointer(&addr)) = p
    52  }
    53  
    54  func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
    55  	addr := base + uintptr(idx)
    56  	p := **(**uintptr)(unsafe.Pointer(&addr))
    57  	for i := uint8(0); i < ptrNum; i++ {
    58  		if p == 0 {
    59  			return 0
    60  		}
    61  		p = ptrToPtr(p)
    62  	}
    63  	return p
    64  }
    65  
    66  func ptrToUint64(p uintptr, bitSize uint8) uint64 {
    67  	switch bitSize {
    68  	case 8:
    69  		return (uint64)(**(**uint8)(unsafe.Pointer(&p)))
    70  	case 16:
    71  		return (uint64)(**(**uint16)(unsafe.Pointer(&p)))
    72  	case 32:
    73  		return (uint64)(**(**uint32)(unsafe.Pointer(&p)))
    74  	case 64:
    75  		return **(**uint64)(unsafe.Pointer(&p))
    76  	}
    77  	return 0
    78  }
    79  
    80  func ptrToFloat32(p uintptr) float32            { return **(**float32)(unsafe.Pointer(&p)) }
    81  func ptrToFloat64(p uintptr) float64            { return **(**float64)(unsafe.Pointer(&p)) }
    82  func ptrToBool(p uintptr) bool                  { return **(**bool)(unsafe.Pointer(&p)) }
    83  func ptrToBytes(p uintptr) []byte               { return **(**[]byte)(unsafe.Pointer(&p)) }
    84  func ptrToNumber(p uintptr) json.Number         { return **(**json.Number)(unsafe.Pointer(&p)) }
    85  func ptrToString(p uintptr) string              { return **(**string)(unsafe.Pointer(&p)) }
    86  func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) }
    87  func ptrToPtr(p uintptr) uintptr {
    88  	return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
    89  }
    90  func ptrToNPtr(p uintptr, ptrNum uint8) uintptr {
    91  	for i := uint8(0); i < ptrNum; i++ {
    92  		if p == 0 {
    93  			return 0
    94  		}
    95  		p = ptrToPtr(p)
    96  	}
    97  	return p
    98  }
    99  
   100  func ptrToUnsafePtr(p uintptr) unsafe.Pointer {
   101  	return *(*unsafe.Pointer)(unsafe.Pointer(&p))
   102  }
   103  func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} {
   104  	return *(*interface{})(unsafe.Pointer(&emptyInterface{
   105  		typ: code.Type,
   106  		ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
   107  	}))
   108  }
   109  
   110  func appendInt(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
   111  	format := ctx.Option.ColorScheme.Int
   112  	b = append(b, format.Header...)
   113  	b = encoder.AppendInt(ctx, b, p, code)
   114  	return append(b, format.Footer...)
   115  }
   116  
   117  func appendUint(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
   118  	format := ctx.Option.ColorScheme.Uint
   119  	b = append(b, format.Header...)
   120  	b = encoder.AppendUint(ctx, b, p, code)
   121  	return append(b, format.Footer...)
   122  }
   123  
   124  func appendFloat32(ctx *encoder.RuntimeContext, b []byte, v float32) []byte {
   125  	format := ctx.Option.ColorScheme.Float
   126  	b = append(b, format.Header...)
   127  	b = encoder.AppendFloat32(ctx, b, v)
   128  	return append(b, format.Footer...)
   129  }
   130  
   131  func appendFloat64(ctx *encoder.RuntimeContext, b []byte, v float64) []byte {
   132  	format := ctx.Option.ColorScheme.Float
   133  	b = append(b, format.Header...)
   134  	b = encoder.AppendFloat64(ctx, b, v)
   135  	return append(b, format.Footer...)
   136  }
   137  
   138  func appendString(ctx *encoder.RuntimeContext, b []byte, v string) []byte {
   139  	format := ctx.Option.ColorScheme.String
   140  	b = append(b, format.Header...)
   141  	b = encoder.AppendString(ctx, b, v)
   142  	return append(b, format.Footer...)
   143  }
   144  
   145  func appendByteSlice(ctx *encoder.RuntimeContext, b []byte, src []byte) []byte {
   146  	format := ctx.Option.ColorScheme.Binary
   147  	b = append(b, format.Header...)
   148  	b = encoder.AppendByteSlice(ctx, b, src)
   149  	return append(b, format.Footer...)
   150  }
   151  
   152  func appendNumber(ctx *encoder.RuntimeContext, b []byte, n json.Number) ([]byte, error) {
   153  	format := ctx.Option.ColorScheme.Int
   154  	b = append(b, format.Header...)
   155  	bb, err := encoder.AppendNumber(ctx, b, n)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	return append(bb, format.Footer...), nil
   160  }
   161  
   162  func appendBool(ctx *encoder.RuntimeContext, b []byte, v bool) []byte {
   163  	format := ctx.Option.ColorScheme.Bool
   164  	b = append(b, format.Header...)
   165  	if v {
   166  		b = append(b, "true"...)
   167  	} else {
   168  		b = append(b, "false"...)
   169  	}
   170  	return append(b, format.Footer...)
   171  }
   172  
   173  func appendNull(ctx *encoder.RuntimeContext, b []byte) []byte {
   174  	format := ctx.Option.ColorScheme.Null
   175  	b = append(b, format.Header...)
   176  	b = append(b, "null"...)
   177  	return append(b, format.Footer...)
   178  }
   179  
   180  func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
   181  	return append(b, ',', '\n')
   182  }
   183  
   184  func appendNullComma(ctx *encoder.RuntimeContext, b []byte) []byte {
   185  	format := ctx.Option.ColorScheme.Null
   186  	b = append(b, format.Header...)
   187  	b = append(b, "null"...)
   188  	return append(append(b, format.Footer...), ',', '\n')
   189  }
   190  
   191  func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
   192  	return append(b[:len(b)-2], ':', ' ')
   193  }
   194  
   195  func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
   196  	b = appendIndent(ctx, b, code.Indent+1)
   197  	b = append(b, key...)
   198  	b[len(b)-2] = ':'
   199  	b[len(b)-1] = ' '
   200  	return append(b, value...)
   201  }
   202  
   203  func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   204  	b = b[:len(b)-2]
   205  	b = append(b, '\n')
   206  	b = appendIndent(ctx, b, code.Indent)
   207  	return append(b, '}', ',', '\n')
   208  }
   209  
   210  func appendArrayHead(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   211  	b = append(b, '[', '\n')
   212  	return appendIndent(ctx, b, code.Indent+1)
   213  }
   214  
   215  func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   216  	b = b[:len(b)-2]
   217  	b = append(b, '\n')
   218  	b = appendIndent(ctx, b, code.Indent)
   219  	return append(b, ']', ',', '\n')
   220  }
   221  
   222  func appendEmptyArray(_ *encoder.RuntimeContext, b []byte) []byte {
   223  	return append(b, '[', ']', ',', '\n')
   224  }
   225  
   226  func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte {
   227  	return append(b, '{', '}', ',', '\n')
   228  }
   229  
   230  func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   231  	last := len(b) - 1
   232  	// replace comma to newline
   233  	b[last-1] = '\n'
   234  	b = appendIndent(ctx, b[:last], code.Indent)
   235  	return append(b, '}', ',', '\n')
   236  }
   237  
   238  func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
   239  	return encoder.AppendMarshalJSONIndent(ctx, code, b, v)
   240  }
   241  
   242  func appendMarshalText(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
   243  	format := ctx.Option.ColorScheme.String
   244  	b = append(b, format.Header...)
   245  	bb, err := encoder.AppendMarshalTextIndent(ctx, code, b, v)
   246  	if err != nil {
   247  		return nil, err
   248  	}
   249  	return append(bb, format.Footer...), nil
   250  }
   251  
   252  func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte {
   253  	return append(b, '{', '\n')
   254  }
   255  
   256  func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   257  	b = appendIndent(ctx, b, code.Indent)
   258  
   259  	format := ctx.Option.ColorScheme.ObjectKey
   260  	b = append(b, format.Header...)
   261  	b = append(b, code.Key[:len(code.Key)-1]...)
   262  	b = append(b, format.Footer...)
   263  
   264  	return append(b, ':', ' ')
   265  }
   266  
   267  func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   268  	last := len(b) - 1
   269  	if b[last-1] == '{' {
   270  		b[last] = '}'
   271  	} else {
   272  		if b[last] == '\n' {
   273  			// to remove ',' and '\n' characters
   274  			b = b[:len(b)-2]
   275  		}
   276  		b = append(b, '\n')
   277  		b = appendIndent(ctx, b, code.Indent-1)
   278  		b = append(b, '}')
   279  	}
   280  	return appendComma(ctx, b)
   281  }
   282  
   283  func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {
   284  	ctx.BaseIndent = uint32(load(ctxptr, code.Length))
   285  }
   286  
   287  func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {
   288  	store(ctxptr, code.Length, indent)
   289  }
   290  
   291  func appendArrayElemIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   292  	return appendIndent(ctx, b, code.Indent+1)
   293  }
   294  
   295  func appendMapKeyIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   296  	return appendIndent(ctx, b, code.Indent)
   297  }