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 }