github.com/3JoB/go-json@v0.10.4/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/3JoB/go-json/internal/encoder"
     9  	"github.com/3JoB/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  
    82  func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
    83  
    84  func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
    85  
    86  func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
    87  
    88  func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) }
    89  
    90  func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
    91  
    92  func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) }
    93  
    94  func ptrToPtr(p uintptr) uintptr {
    95  	return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
    96  }
    97  
    98  func ptrToNPtr(p uintptr, ptrNum uint8) uintptr {
    99  	for i := uint8(0); i < ptrNum; i++ {
   100  		if p == 0 {
   101  			return 0
   102  		}
   103  		p = ptrToPtr(p)
   104  	}
   105  	return p
   106  }
   107  
   108  func ptrToUnsafePtr(p uintptr) unsafe.Pointer {
   109  	return *(*unsafe.Pointer)(unsafe.Pointer(&p))
   110  }
   111  
   112  func ptrToInterface(code *encoder.Opcode, p uintptr) any {
   113  	return *(*any)(unsafe.Pointer(&emptyInterface{
   114  		typ: code.Type,
   115  		ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
   116  	}))
   117  }
   118  
   119  func appendInt(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
   120  	format := ctx.Option.ColorScheme.Int
   121  	b = append(b, format.Header...)
   122  	b = encoder.AppendInt(ctx, b, p, code)
   123  	return append(b, format.Footer...)
   124  }
   125  
   126  func appendUint(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
   127  	format := ctx.Option.ColorScheme.Uint
   128  	b = append(b, format.Header...)
   129  	b = encoder.AppendUint(ctx, b, p, code)
   130  	return append(b, format.Footer...)
   131  }
   132  
   133  func appendFloat32(ctx *encoder.RuntimeContext, b []byte, v float32) []byte {
   134  	format := ctx.Option.ColorScheme.Float
   135  	b = append(b, format.Header...)
   136  	b = encoder.AppendFloat32(ctx, b, v)
   137  	return append(b, format.Footer...)
   138  }
   139  
   140  func appendFloat64(ctx *encoder.RuntimeContext, b []byte, v float64) []byte {
   141  	format := ctx.Option.ColorScheme.Float
   142  	b = append(b, format.Header...)
   143  	b = encoder.AppendFloat64(ctx, b, v)
   144  	return append(b, format.Footer...)
   145  }
   146  
   147  func appendString(ctx *encoder.RuntimeContext, b []byte, v string) []byte {
   148  	format := ctx.Option.ColorScheme.String
   149  	b = append(b, format.Header...)
   150  	b = encoder.AppendString(ctx, b, v)
   151  	return append(b, format.Footer...)
   152  }
   153  
   154  func appendByteSlice(ctx *encoder.RuntimeContext, b []byte, src []byte) []byte {
   155  	format := ctx.Option.ColorScheme.Binary
   156  	b = append(b, format.Header...)
   157  	b = encoder.AppendByteSlice(ctx, b, src)
   158  	return append(b, format.Footer...)
   159  }
   160  
   161  func appendNumber(ctx *encoder.RuntimeContext, b []byte, n json.Number) ([]byte, error) {
   162  	format := ctx.Option.ColorScheme.Int
   163  	b = append(b, format.Header...)
   164  	bb, err := encoder.AppendNumber(ctx, b, n)
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  	return append(bb, format.Footer...), nil
   169  }
   170  
   171  func appendBool(ctx *encoder.RuntimeContext, b []byte, v bool) []byte {
   172  	format := ctx.Option.ColorScheme.Bool
   173  	b = append(b, format.Header...)
   174  	if v {
   175  		b = append(b, "true"...)
   176  	} else {
   177  		b = append(b, "false"...)
   178  	}
   179  	return append(b, format.Footer...)
   180  }
   181  
   182  func appendNull(ctx *encoder.RuntimeContext, b []byte) []byte {
   183  	format := ctx.Option.ColorScheme.Null
   184  	b = append(b, format.Header...)
   185  	b = append(b, "null"...)
   186  	return append(b, format.Footer...)
   187  }
   188  
   189  func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
   190  	return append(b, ',', '\n')
   191  }
   192  
   193  func appendNullComma(ctx *encoder.RuntimeContext, b []byte) []byte {
   194  	format := ctx.Option.ColorScheme.Null
   195  	b = append(b, format.Header...)
   196  	b = append(b, "null"...)
   197  	return append(append(b, format.Footer...), ',', '\n')
   198  }
   199  
   200  func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
   201  	return append(b[:len(b)-2], ':', ' ')
   202  }
   203  
   204  func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
   205  	b = appendIndent(ctx, b, code.Indent+1)
   206  	b = append(b, key...)
   207  	b[len(b)-2] = ':'
   208  	b[len(b)-1] = ' '
   209  	return append(b, value...)
   210  }
   211  
   212  func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   213  	b = b[:len(b)-2]
   214  	b = append(b, '\n')
   215  	b = appendIndent(ctx, b, code.Indent)
   216  	return append(b, '}', ',', '\n')
   217  }
   218  
   219  func appendArrayHead(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   220  	b = append(b, '[', '\n')
   221  	return appendIndent(ctx, b, code.Indent+1)
   222  }
   223  
   224  func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   225  	b = b[:len(b)-2]
   226  	b = append(b, '\n')
   227  	b = appendIndent(ctx, b, code.Indent)
   228  	return append(b, ']', ',', '\n')
   229  }
   230  
   231  func appendEmptyArray(_ *encoder.RuntimeContext, b []byte) []byte {
   232  	return append(b, '[', ']', ',', '\n')
   233  }
   234  
   235  func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte {
   236  	return append(b, '{', '}', ',', '\n')
   237  }
   238  
   239  func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   240  	last := len(b) - 1
   241  	// replace comma to newline
   242  	b[last-1] = '\n'
   243  	b = appendIndent(ctx, b[:last], code.Indent)
   244  	return append(b, '}', ',', '\n')
   245  }
   246  
   247  func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v any) ([]byte, error) {
   248  	return encoder.AppendMarshalJSONIndent(ctx, code, b, v)
   249  }
   250  
   251  func appendMarshalText(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v any) ([]byte, error) {
   252  	format := ctx.Option.ColorScheme.String
   253  	b = append(b, format.Header...)
   254  	bb, err := encoder.AppendMarshalTextIndent(ctx, code, b, v)
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  	return append(bb, format.Footer...), nil
   259  }
   260  
   261  func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte {
   262  	return append(b, '{', '\n')
   263  }
   264  
   265  func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   266  	b = appendIndent(ctx, b, code.Indent)
   267  
   268  	format := ctx.Option.ColorScheme.ObjectKey
   269  	b = append(b, format.Header...)
   270  	b = append(b, code.Key[:len(code.Key)-1]...)
   271  	b = append(b, format.Footer...)
   272  
   273  	return append(b, ':', ' ')
   274  }
   275  
   276  func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   277  	last := len(b) - 1
   278  	if b[last-1] == '{' {
   279  		b[last] = '}'
   280  	} else {
   281  		if b[last] == '\n' {
   282  			// to remove ',' and '\n' characters
   283  			b = b[:len(b)-2]
   284  		}
   285  		b = append(b, '\n')
   286  		b = appendIndent(ctx, b, code.Indent-1)
   287  		b = append(b, '}')
   288  	}
   289  	return appendComma(ctx, b)
   290  }
   291  
   292  func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {
   293  	ctx.BaseIndent = uint32(load(ctxptr, code.Length))
   294  }
   295  
   296  func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {
   297  	store(ctxptr, code.Length, indent)
   298  }
   299  
   300  func appendArrayElemIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   301  	return appendIndent(ctx, b, code.Indent+1)
   302  }
   303  
   304  func appendMapKeyIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
   305  	return appendIndent(ctx, b, code.Indent)
   306  }