Files
phishingclub/backend/vendor/github.com/ysmood/gson/write.go
T
Ronni Skansing f5e6f53d75 update vendor
Signed-off-by: Ronni Skansing <rskansing@gmail.com>
2026-05-24 09:57:07 +02:00

176 lines
3.4 KiB
Go

package gson
import (
"encoding/json"
"io"
"reflect"
"sync"
)
// New JSON from []byte, [io.Reader], or raw value.
func New(v interface{}) JSON {
return JSON{&sync.Mutex{}, &v}
}
// NewFrom json encoded string
func NewFrom(s string) JSON {
return New([]byte(s))
}
// UnmarshalJSON interface
func (j *JSON) UnmarshalJSON(b []byte) error {
*j = New(b)
return nil
}
// Val of the underlying json value.
// The first time it's called, it will try to parse the underlying data.
func (j JSON) Val() interface{} {
if j.value == nil {
return nil
}
j.lock.Lock()
defer j.lock.Unlock()
for {
val, ok := (*j.value).(JSON)
if ok {
*j.value = *val.value
} else {
break
}
}
var val interface{}
switch v := (*j.value).(type) {
case []byte:
_ = json.Unmarshal(v, &val)
*j.value = val
case io.Reader:
_ = json.NewDecoder(v).Decode(&val)
*j.value = val
}
return *j.value
}
// Set by json path. It's a shortcut for Sets.
func (j *JSON) Set(path string, val interface{}) *JSON {
return j.Sets(val, Path(path)...)
}
var _map map[string]interface{}
var interfaceType = reflect.TypeOf(_map).Elem()
// Sets element by path sections. If a section is not string or int, it will be ignored.
func (j *JSON) Sets(target interface{}, sections ...interface{}) *JSON {
if j.value == nil {
*j = New(nil)
}
last := len(sections) - 1
val := reflect.ValueOf(j.Val())
override := func(v reflect.Value) {
*j.value = v.Interface()
}
if last == -1 {
*j.value = target
return j
}
for i, s := range sections {
sect := reflect.ValueOf(s)
if val.Kind() == reflect.Interface {
val = val.Elem()
}
switch sect.Kind() {
case reflect.Int:
k := int(sect.Int())
if val.Kind() != reflect.Slice || val.Len() <= k {
nArr := reflect.ValueOf(make([]interface{}, k+1))
if val.Kind() == reflect.Slice {
reflect.Copy(nArr, val)
}
val = nArr
override(val)
}
if i == last {
val.Index(k).Set(reflect.ValueOf(target))
return j
}
prev := val
val = val.Index(k)
override = func(v reflect.Value) {
prev.Index(k).Set(v)
}
default:
targetVal := reflect.ValueOf(target)
if val.Kind() != reflect.Map {
val = reflect.MakeMap(reflect.MapOf(sect.Type(), interfaceType))
override(val)
}
if i == last {
val.SetMapIndex(sect, targetVal)
}
prev := val
val = val.MapIndex(sect)
override = func(v reflect.Value) {
prev.SetMapIndex(sect, v)
}
}
}
return j
}
// Del deletes the element at the path.
func (j *JSON) Del(path string) *JSON {
j.Dels(Path(path)...)
return j
}
// Dels deletes the element at the path sections.
// Return true if it's deleted.
func (j *JSON) Dels(sections ...interface{}) bool {
l := len(sections)
if l == 0 {
j.value = nil
return true
}
last := sections[l-1]
parent, has := j.Gets(sections[:l-1]...)
if !has {
return false
}
parentVal := reflect.ValueOf(parent.Val())
lastVal := reflect.ValueOf(last)
switch k := last.(type) {
case int:
pl := parentVal.Len()
if parentVal.Kind() != reflect.Slice || k < 0 || k >= pl {
return false
}
j.Sets(reflect.AppendSlice(
parentVal.Slice(0, k),
parentVal.Slice(k+1, pl),
).Interface(), sections[:l-1]...)
default:
if parentVal.Kind() != reflect.Map || !lastVal.Type().AssignableTo(parentVal.Type().Key()) {
return false
}
parentVal.SetMapIndex(lastVal, reflect.Value{})
}
return true
}