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  }