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 }