api.go raw
1 //go:build (amd64 && go1.17 && !go1.25) || (arm64 && go1.20 && !go1.25)
2 // +build amd64,go1.17,!go1.25 arm64,go1.20,!go1.25
3
4 /*
5 * Copyright 2022 ByteDance Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 package ast
21
22 import (
23 `runtime`
24 `unsafe`
25
26 `github.com/bytedance/sonic/encoder`
27 `github.com/bytedance/sonic/internal/native`
28 `github.com/bytedance/sonic/internal/native/types`
29 `github.com/bytedance/sonic/internal/rt`
30 uq `github.com/bytedance/sonic/unquote`
31 `github.com/bytedance/sonic/utf8`
32 )
33
34 var typeByte = rt.UnpackEface(byte(0)).Type
35
36 //go:nocheckptr
37 func quote(buf *[]byte, val string) {
38 *buf = append(*buf, '"')
39 if len(val) == 0 {
40 *buf = append(*buf, '"')
41 return
42 }
43
44 sp := rt.IndexChar(val, 0)
45 nb := len(val)
46 b := (*rt.GoSlice)(unsafe.Pointer(buf))
47
48 // input buffer
49 for nb > 0 {
50 // output buffer
51 dp := unsafe.Pointer(uintptr(b.Ptr) + uintptr(b.Len))
52 dn := b.Cap - b.Len
53 // call native.Quote, dn is byte count it outputs
54 ret := native.Quote(sp, nb, dp, &dn, 0)
55 // update *buf length
56 b.Len += dn
57
58 // no need more output
59 if ret >= 0 {
60 break
61 }
62
63 // double buf size
64 *b = rt.GrowSlice(typeByte, *b, b.Cap*2)
65 // ret is the complement of consumed input
66 ret = ^ret
67 // update input buffer
68 nb -= ret
69 sp = unsafe.Pointer(uintptr(sp) + uintptr(ret))
70 }
71
72 runtime.KeepAlive(buf)
73 runtime.KeepAlive(sp)
74 *buf = append(*buf, '"')
75 }
76
77 func unquote(src string) (string, types.ParsingError) {
78 return uq.String(src)
79 }
80
81 func (self *Parser) decodeValue() (val types.JsonState) {
82 sv := (*rt.GoString)(unsafe.Pointer(&self.s))
83 flag := types.F_USE_NUMBER
84 if self.dbuf != nil {
85 flag = 0
86 val.Dbuf = self.dbuf
87 val.Dcap = types.MaxDigitNums
88 }
89 self.p = native.Value(sv.Ptr, sv.Len, self.p, &val, uint64(flag))
90 return
91 }
92
93 func (self *Parser) skip() (int, types.ParsingError) {
94 fsm := types.NewStateMachine()
95 start := native.SkipOne(&self.s, &self.p, fsm, 0)
96 types.FreeStateMachine(fsm)
97
98 if start < 0 {
99 return self.p, types.ParsingError(-start)
100 }
101 return start, 0
102 }
103
104 func (self *Node) encodeInterface(buf *[]byte) error {
105 //WARN: NOT compatible with json.Encoder
106 return encoder.EncodeInto(buf, self.packAny(), encoder.NoEncoderNewline)
107 }
108
109 func (self *Parser) skipFast() (int, types.ParsingError) {
110 start := native.SkipOneFast(&self.s, &self.p)
111 if start < 0 {
112 return self.p, types.ParsingError(-start)
113 }
114 return start, 0
115 }
116
117 func (self *Parser) getByPath(validate bool, path ...interface{}) (int, types.ParsingError) {
118 var fsm *types.StateMachine
119 if validate {
120 fsm = types.NewStateMachine()
121 }
122 start := native.GetByPath(&self.s, &self.p, &path, fsm)
123 if validate {
124 types.FreeStateMachine(fsm)
125 }
126 runtime.KeepAlive(path)
127 if start < 0 {
128 return self.p, types.ParsingError(-start)
129 }
130 return start, 0
131 }
132
133 func validate_utf8(str string) bool {
134 return utf8.ValidateString(str)
135 }
136