github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zjson/json.go (about) 1 // Package zjson json data read and write operations 2 package zjson 3 4 import ( 5 jsongo "encoding/json" 6 "errors" 7 "strconv" 8 "unsafe" 9 10 "github.com/sohaha/zlsgo/zstring" 11 ) 12 13 var ( 14 ErrNoChange = errors.New("no change") 15 ErrPathEmpty = errors.New("path cannot be empty") 16 ErrInvalidJSON = errors.New("invalid json") 17 ErrNotAllowedWildcard = errors.New("wildcard characters not allowed in path") 18 ErrNotAllowedArrayAccess = errors.New("array access character not allowed in path") 19 ErrTypeError = errors.New("json must be an object or array") 20 ) 21 22 func (r *Res) MatchKeys(keys []string) *Res { 23 return r.Filter(func(key, value *Res) bool { 24 for i := range keys { 25 if key.String() == keys[i] { 26 return true 27 } 28 } 29 return false 30 }) 31 } 32 33 func (r *Res) Filter(fn func(key, value *Res) bool) *Res { 34 j := "{}" 35 r.ForEach(func(key, value *Res) bool { 36 if fn(key, value) { 37 j, _ = Set(j, key.String(), value.Value()) 38 } 39 return true 40 }) 41 return Parse(j) 42 } 43 44 type stringHeader struct { 45 data unsafe.Pointer 46 len int 47 } 48 49 func fillIndex(json string, c *parseContext) { 50 if len(c.value.raw) > 0 && !c.calcd { 51 jhdr := *(*stringHeader)(unsafe.Pointer(&json)) 52 rhdr := *(*stringHeader)(unsafe.Pointer(&(c.value.raw))) 53 c.value.index = int(uintptr(rhdr.data) - uintptr(jhdr.data)) 54 if c.value.index < 0 || c.value.index >= len(json) { 55 c.value.index = 0 56 } 57 } 58 } 59 60 func set(s, path, raw string, stringify, del, optimistic, place bool) ([]byte, error) { 61 if path == "" { 62 if !Valid(raw) { 63 return nil, ErrPathEmpty 64 } 65 return zstring.String2Bytes(raw), nil 66 } 67 if !del && optimistic && isOptimisticPath(path) { 68 res := Get(s, path) 69 if res.Exists() && res.index > 0 { 70 sz := len(s) - len(res.raw) + len(raw) 71 if stringify { 72 sz += 2 73 } 74 if place && sz <= len(s) { 75 if !stringify || !mustMarshalString(raw) { 76 jbytes := []byte(s) 77 if stringify { 78 jbytes[res.index] = '"' 79 copy(jbytes[res.index+1:], zstring.String2Bytes(raw)) 80 jbytes[res.index+1+len(raw)] = '"' 81 copy(jbytes[res.index+1+len(raw)+1:], 82 jbytes[res.index+len(res.raw):]) 83 } else { 84 copy(jbytes[res.index:], zstring.String2Bytes(raw)) 85 copy(jbytes[res.index+len(raw):], 86 jbytes[res.index+len(res.raw):]) 87 } 88 return jbytes[:sz], nil 89 } 90 return nil, nil 91 } 92 buf := make([]byte, 0, sz) 93 buf = append(buf, s[:res.index]...) 94 if stringify { 95 buf = appendStringify(buf, raw) 96 } else { 97 buf = append(buf, raw...) 98 } 99 buf = append(buf, s[res.index+len(res.raw):]...) 100 return buf, nil 101 } 102 } 103 paths := make([]pathResult, 0, 4) 104 r, err := parsePath(path) 105 if err != nil { 106 return nil, err 107 } 108 paths = append(paths, r) 109 for r.more { 110 if r, err = parsePath(r.path); err != nil { 111 return nil, err 112 } 113 paths = append(paths, r) 114 } 115 116 njson, err := appendRawPaths(nil, s, paths, raw, stringify, del) 117 if err != nil { 118 return nil, err 119 } 120 return njson, nil 121 } 122 123 func SetOptions(json, path string, value interface{}, 124 opts *Options) (string, error) { 125 if opts != nil && opts.ReplaceInPlace { 126 nopts := *opts 127 opts = &nopts 128 opts.ReplaceInPlace = false 129 } 130 if json == "" { 131 json = "{}" 132 } 133 jsonb := zstring.String2Bytes(json) 134 res, err := SetBytesOptions(jsonb, path, value, opts) 135 return zstring.Bytes2String(res), err 136 } 137 138 func SetBytesOptions(json []byte, path string, value interface{}, 139 opts *Options) ([]byte, error) { 140 var optimistic, inplace bool 141 if opts != nil { 142 optimistic = opts.Optimistic 143 inplace = opts.ReplaceInPlace 144 } 145 jstr := zstring.Bytes2String(json) 146 var res []byte 147 var err error 148 switch v := value.(type) { 149 default: 150 b, merr := jsongo.Marshal(value) 151 if merr != nil { 152 return nil, merr 153 } 154 raw := zstring.Bytes2String(b) 155 res, err = set(jstr, path, raw, false, false, optimistic, inplace) 156 case dtype: 157 res, err = set(jstr, path, "", false, true, optimistic, inplace) 158 case string: 159 res, err = set(jstr, path, v, true, false, optimistic, inplace) 160 case []byte: 161 raw := zstring.Bytes2String(v) 162 res, err = set(jstr, path, raw, true, false, optimistic, inplace) 163 case bool: 164 if v { 165 res, err = set(jstr, path, "true", false, false, optimistic, inplace) 166 } else { 167 res, err = set(jstr, path, "false", false, false, optimistic, inplace) 168 } 169 case int: 170 res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), 171 false, false, optimistic, inplace) 172 case int8: 173 res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), 174 false, false, optimistic, inplace) 175 case int16: 176 res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), 177 false, false, optimistic, inplace) 178 case int32: 179 res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), 180 false, false, optimistic, inplace) 181 case int64: 182 res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), 183 false, false, optimistic, inplace) 184 case uint: 185 res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), 186 false, false, optimistic, inplace) 187 case uint8: 188 res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), 189 false, false, optimistic, inplace) 190 case uint16: 191 res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), 192 false, false, optimistic, inplace) 193 case uint32: 194 res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), 195 false, false, optimistic, inplace) 196 case uint64: 197 res, err = set(jstr, path, strconv.FormatUint(v, 10), 198 false, false, optimistic, inplace) 199 case float32: 200 res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64), 201 false, false, optimistic, inplace) 202 case float64: 203 res, err = set(jstr, path, strconv.FormatFloat(v, 'f', -1, 64), 204 false, false, optimistic, inplace) 205 } 206 if err == ErrNoChange { 207 return json, nil 208 } 209 return res, err 210 } 211 212 func SetRawBytesOptions(json []byte, path string, value []byte, 213 opts *Options) ([]byte, error) { 214 jstr := zstring.Bytes2String(json) 215 vstr := zstring.Bytes2String(value) 216 var optimistic, inplace bool 217 if opts != nil { 218 optimistic = opts.Optimistic 219 inplace = opts.ReplaceInPlace 220 } 221 res, err := set(jstr, path, vstr, false, false, optimistic, inplace) 222 if err == ErrNoChange { 223 return json, nil 224 } 225 return res, err 226 } 227 228 func safeInt(f float64) (n int, ok bool) { 229 if f < -9007199254740991 || f > 9007199254740991 { 230 return 0, false 231 } 232 return int(f), true 233 } 234 235 func squash(json string) string { 236 ss, _ := switchJson(json, 0, false) 237 return ss 238 } 239 240 func parseSquash(json string, i int) (string, int) { 241 return switchJson(json, i, true) 242 }