mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-01-23 14:50:21 +00:00
170 lines
3.1 KiB
Go
170 lines
3.1 KiB
Go
|
package optdec
|
||
|
|
||
|
import (
|
||
|
"encoding"
|
||
|
"encoding/json"
|
||
|
"unsafe"
|
||
|
"reflect"
|
||
|
|
||
|
"github.com/bytedance/sonic/internal/rt"
|
||
|
)
|
||
|
|
||
|
type efaceDecoder struct {
|
||
|
}
|
||
|
|
||
|
func (d *efaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||
|
if node.IsNull() {
|
||
|
*(*interface{})(vp) = interface{}(nil)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
eface := *(*rt.GoEface)(vp)
|
||
|
|
||
|
// not pointer type, or nil pointer, or *interface{}
|
||
|
if eface.Value == nil || eface.Type.Kind() != reflect.Ptr || rt.PtrElem(eface.Type) == anyType {
|
||
|
ret, err := node.AsEface(ctx)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
*(*interface{})(vp) = ret
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
etp := rt.PtrElem(eface.Type)
|
||
|
vp = eface.Value
|
||
|
|
||
|
/* check the defined pointer type for issue 379 */
|
||
|
if eface.Type.IsNamed() {
|
||
|
newp := vp
|
||
|
etp = eface.Type
|
||
|
vp = unsafe.Pointer(&newp)
|
||
|
}
|
||
|
|
||
|
dec, err := findOrCompile(etp)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return dec.FromDom(vp, node, ctx)
|
||
|
}
|
||
|
|
||
|
type ifaceDecoder struct {
|
||
|
typ *rt.GoType
|
||
|
}
|
||
|
|
||
|
func (d *ifaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||
|
if node.IsNull() {
|
||
|
*(*unsafe.Pointer)(vp) = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
iface := *(*rt.GoIface)(vp)
|
||
|
if iface.Itab == nil {
|
||
|
return error_type(d.typ)
|
||
|
}
|
||
|
|
||
|
vt := iface.Itab.Vt
|
||
|
|
||
|
// not pointer type, or nil pointer, or *interface{}
|
||
|
if vp == nil || vt.Kind() != reflect.Ptr || rt.PtrElem(vt) == anyType {
|
||
|
ret, err := node.AsEface(ctx)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
*(*interface{})(vp) = ret
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
|
||
|
etp := rt.PtrElem(vt)
|
||
|
vp = iface.Value
|
||
|
|
||
|
/* check the defined pointer type for issue 379 */
|
||
|
if vt.IsNamed() {
|
||
|
newp := vp
|
||
|
etp = vt
|
||
|
vp = unsafe.Pointer(&newp)
|
||
|
}
|
||
|
|
||
|
dec, err := findOrCompile(etp)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return dec.FromDom(vp, node, ctx)
|
||
|
}
|
||
|
|
||
|
type unmarshalTextDecoder struct {
|
||
|
typ *rt.GoType
|
||
|
}
|
||
|
|
||
|
func (d *unmarshalTextDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||
|
if node.IsNull() {
|
||
|
*(*unsafe.Pointer)(vp) = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
txt, ok := node.AsStringText(ctx)
|
||
|
if !ok {
|
||
|
return error_mismatch(node, ctx, d.typ.Pack())
|
||
|
}
|
||
|
|
||
|
v := *(*interface{})(unsafe.Pointer(&rt.GoEface{
|
||
|
Type: d.typ,
|
||
|
Value: vp,
|
||
|
}))
|
||
|
|
||
|
// fast path
|
||
|
if u, ok := v.(encoding.TextUnmarshaler); ok {
|
||
|
return u.UnmarshalText(txt)
|
||
|
}
|
||
|
|
||
|
// slow path
|
||
|
rv := reflect.ValueOf(v)
|
||
|
if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
|
||
|
return u.UnmarshalText(txt)
|
||
|
}
|
||
|
|
||
|
return error_type(d.typ)
|
||
|
}
|
||
|
|
||
|
type unmarshalJSONDecoder struct {
|
||
|
typ *rt.GoType
|
||
|
strOpt bool
|
||
|
}
|
||
|
|
||
|
func (d *unmarshalJSONDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||
|
v := *(*interface{})(unsafe.Pointer(&rt.GoEface{
|
||
|
Type: d.typ,
|
||
|
Value: vp,
|
||
|
}))
|
||
|
|
||
|
var input []byte
|
||
|
if d.strOpt && node.IsNull() {
|
||
|
input = []byte("null")
|
||
|
} else if d.strOpt {
|
||
|
s, ok := node.AsStringText(ctx)
|
||
|
if !ok {
|
||
|
return error_mismatch(node, ctx, d.typ.Pack())
|
||
|
}
|
||
|
input = s
|
||
|
} else {
|
||
|
input = []byte(node.AsRaw(ctx))
|
||
|
}
|
||
|
|
||
|
// fast path
|
||
|
if u, ok := v.(json.Unmarshaler); ok {
|
||
|
return u.UnmarshalJSON((input))
|
||
|
}
|
||
|
|
||
|
// slow path
|
||
|
rv := reflect.ValueOf(v)
|
||
|
if u, ok := rv.Interface().(json.Unmarshaler); ok {
|
||
|
return u.UnmarshalJSON(input)
|
||
|
}
|
||
|
|
||
|
return error_type(d.typ)
|
||
|
}
|